web-dev-qa-db-fra.com

Pourquoi gc () ne libère-t-il pas de mémoire?

J'exécute des simulations sur un ordinateur Windows 64 bits avec 64 Go de RAM. L'utilisation de la mémoire atteint 55% et après une simulation terminée, je supprime tous les objets dans l'espace de travail par rm(list=ls()), suivi par double gc().

Je supposais que cela libérerait suffisamment de mémoire pour la prochaine simulation, mais en fait l'utilisation de la mémoire baisse de seulement 1%. En consultant beaucoup de forums différents, je n'ai pas pu trouver d'explication satisfaisante, seulement de vagues commentaires tels que:

"Selon votre système d'exploitation, la mémoire libérée peut ne pas être renvoyée au système d'exploitation, mais conservée dans l'espace de processus."

J'aimerais trouver des informations sur:

  • 1) quel système d'exploitation et dans quelles conditions la mémoire libérée n'est pas renvoyée au système d'exploitation, et
  • 2) s'il existe un autre moyen que de fermer R et de le redémarrer pour la prochaine simulation?
56
user7417

Comment vérifiez-vous l'utilisation de la mémoire? Normalement, la machine virtuelle alloue une partie de la mémoire qu'elle utilise pour stocker ses données. Certains des crédits alloués peuvent être inutilisés et marqués comme gratuits. Ce que GC fait est de découvrir des données qui ne sont référencées nulle part ailleurs et de marquer des morceaux de mémoire correspondants comme inutilisés, cela ne signifie pas que cette mémoire est libérée sur le système d'exploitation. Toujours du point de vue VM, il y a maintenant plus de mémoire libre qui peut être utilisée pour d'autres calculs.

Comme d'autres l'ont demandé, avez-vous rencontré des erreurs de mémoire insuffisante? Sinon, il n'y a rien à craindre.

EDIT: This and this devrait être suffisant pour comprendre comment l'allocation de mémoire et le ramasse-miettes fonctionnent dans R.

Du premier document:

Parfois, une tentative est faite pour libérer les pages inutilisées vers le système d'exploitation. Lorsque des pages sont publiées, un nombre de nœuds libres égal à R_MaxKeepFrac multiplié par le nombre de nœuds alloués pour chaque classe est conservé. Les pages non nécessaires pour répondre à cette exigence sont publiées. Une tentative de libération des pages est effectuée pour chaque collection R_PageReleaseFreq de niveau 1 ou de niveau 2.

EDIT2:

Pour voir la mémoire utilisée, essayez d'exécuter gc () avec verbose réglé sur TRUE:

gc(verbose=T)

Voici un résultat avec un tableau de 10'000'000 entiers en mémoire:

Garbage collection 9 = 1+0+8 (level 2) ... 
10.7 Mbytes of cons cells used (49%)
40.6 Mbytes of vectors used (72%)
          used (Mb) gc trigger (Mb) max used (Mb)
Ncells  198838 10.7     407500 21.8   350000 18.7
Vcells 5311050 40.6    7421749 56.7  5311504 40.6

Et voici après avoir supprimé la référence:

Garbage collection 10 = 1+0+9 (level 2) ... 
10.7 Mbytes of cons cells used (49%)
2.4 Mbytes of vectors used (5%)
         used (Mb) gc trigger (Mb) max used (Mb)
Ncells 198821 10.7     407500 21.8   350000 18.7
Vcells 310987  2.4    5937399 45.3  5311504 40.6

Comme vous pouvez le voir, la mémoire utilisée par les Vcell est passée de 40,6 Mo à 2,4 Mo.

23
Ivan Koblik

Le R garbage collector est imparfait de la manière subtile (pas si) suivante: il fait pas déplace les objets (c'est-à-dire qu'il ne fait pas compact = mémoire) en raison de la façon dont il interagit avec les bibliothèques C. (Certains autres langages/implémentations en souffrent aussi, mais d'autres , même s'ils doivent également interagir avec C, parviennent à avoir un compactage GC générationnel qui ne pas souffre de ce problème).

Cela signifie que si vous allouez à tour de rôle de petits morceaux de mémoire qui sont ensuite supprimés et des morceaux plus grands pour des objets plus permanents (c'est une situation courante lors du traitement de chaîne/expression régulière), alors votre mémoire devient fragmentée et le garbage collector ne peut rien y faire: la mémoire est libérée, mais ne peut pas être réutilisée car les morceaux libres sont trop courts.

La seule façon de résoudre le problème consiste à enregistrer les objets souhaités, à redémarrer R et à recharger les objets.

Puisque vous faites rm(list=ls()), c'est-à-dire que vous n'avez besoin d'aucun objet, vous n'avez pas besoin d'enregistrer et de recharger quoi que ce soit, donc, dans votre cas, la solution est précisément ce que vous voulez éviter - redémarrer R.

PS. La collecte des ordures est un sujet très simple. Par exemple, Ruby a utilisé 5 (!) Algorithmes GC différents sur 20 ans . Java GC ne suce pas car Sun/ Oracle et IBM dépensé de nombreuses années de programmeur sur leurs implémentations respectives du GC. D'un autre côté, R et Python ont un GC moche - parce que personne ne dérangeait investir les années-homme nécessaires - et ils sont très populaires. C'est le pire est le mieux pour vous.

PPS. Connexes: R: manque de mémoire en utilisant `strsplit`

28
sds