web-dev-qa-db-fra.com

Pourquoi un ndarray NumPy de 352 Go peut-il être utilisé sur un ordinateur macOS à 8 Go de mémoire?

import numpy as np

array = np.zeros((210000, 210000)) # default numpy.float64
array.nbytes

Lorsque j'exécute le code ci-dessus sur mon MacBook à mémoire de 8 Go avec macOS, aucune erreur ne se produit. Mais en exécutant le même code sur un PC de mémoire de 16 Go avec Windows 10, ou un ordinateur portable Ubuntu de 12 Go de mémoire, ou même sur un supercalculateur Linux de 128 Go de mémoire, l'interpréteur Python déclenchera une MemoryError. Tout le test les environnements ont 64 bits Python 3.6 ou 3.7 installé.

25
Blaise Wang

réponse de @ Martijn Pieters est sur la bonne voie, mais pas tout à fait raison: cela n'a rien à voir avec la compression de la mémoire, mais à la place avec mémoire virtuelle .

Par exemple, essayez d'exécuter le code suivant sur votre ordinateur:

arrays = [np.zeros((21000, 21000)) for _ in range(0, 10000)]

Ce code alloue 32 To de mémoire, mais vous n'obtiendrez pas d'erreur (du moins je ne l'ai pas fait, sous Linux). Si je vérifie htop, je vois ce qui suit:

  PID USER      PRI  NI  VIRT   RES   SHR S CPU% MEM%   TIME+  Command
31362 user       20   0 32.1T 69216 12712 S  0.0  0.4  0:00.22 python

Cela parce que le système d'exploitation est parfaitement disposé à surcharger sur la mémoire virtuelle . Il n'attribuera pas réellement les pages à la mémoire physique jusqu'à ce qu'il en ait besoin. La façon dont cela fonctionne est:

  • calloc demande au système d'exploitation de la mémoire à utiliser
  • le système d'exploitation regarde dans les tables de pages du processus et trouve un morceau de mémoire qu'il est prêt à affecter. C'est une opération rapide, le système d'exploitation stocke simplement la plage d'adresses mémoire dans une structure de données interne.
  • le programme écrit dans l'une des adresses.
  • l'OS reçoit un défaut de page , auquel point il regarde et affecte réellement la page à la mémoire physique. ne page fait généralement quelques Kio .
  • l'OS passe le contrôle au programme, qui se poursuit sans remarquer l'interruption.

La création d'un seul tableau énorme ne fonctionne pas sous Linux car, par défaut, un "un algorithme heuristique est appliqué pour déterminer si suffisamment de mémoire est disponible". ( merci @Martijn Pieters! ) Certaines expériences sur mon système montrent que pour moi, le noyau ne veut pas fournir plus de 0x3BAFFFFFF Octets. Cependant, si j'exécute echo 1 | Sudo tee /proc/sys/vm/overcommit_memory, Puis réessaye le programme dans l'OP, cela fonctionne très bien.

Pour le plaisir, essayez d'exécuter arrays = [np.ones((21000, 21000)) for _ in range(0, 10000)]. Vous obtiendrez certainement une erreur de mémoire insuffisante, même sur MacOs ou Linux avec compression de swap. Oui, certains systèmes d'exploitation peuvent compresser la RAM, mais ils ne peuvent pas la compresser au niveau que vous ne manqueriez pas de mémoire.

23
user60561