155 votes

Comment libérer de la mémoire en Java ?

Existe-t-il un moyen de libérer de la mémoire en Java, similaire à celui du C ? free() fonction ? Ou est-ce que la seule option est de mettre l'objet à null et de s'en remettre à la GC ?

158 votes

Ok... mettons une chose au clair. Ce n'est pas parce que vous pensez qu'une chose est une mauvaise pratique et qu'il ne faut pas l'encourager à la faire, qu'elle mérite un vote négatif. Il s'agit d'une question claire et valide, demandant s'il existe un moyen de libérer de la mémoire en Java sans dépendre du garbage collection. Bien que cela puisse être découragé et généralement pas utile ou une bonne idée, vous ne pouvez pas savoir qu'il n'y a pas de scénarios où il peut être nécessaire sans savoir ce que Felix sait. Felix n'a peut-être même pas l'intention de l'utiliser. Il peut simplement vouloir savoir si c'est possible. Cela ne mérite en aucun cas un vote négatif.

7 votes

À titre de précision, cette remarque s'adresse à la personne qui a voté contre ce projet, et pas nécessairement aux commentaires précédents.

98voto

Daniel Pryden Points 22167

Java utilise de la mémoire gérée, de sorte que la seule façon d'allouer de la mémoire est d'utiliser l'attribut new et la seule façon de désallouer la mémoire est de s'en remettre au ramasseur d'ordures.

Este livre blanc sur la gestion de la mémoire (PDF) peut aider à expliquer ce qui se passe.

Vous pouvez également appeler System.gc() pour suggérer que le ramasseur de déchets s'exécute immédiatement. Toutefois, c'est le Runtime Java qui prend la décision finale, et non votre code.

Selon le [Documentation Java](http://docs.oracle.com/javase/7/docs/api/java/lang/System.html#gc()) ,

L'appel de la méthode gc suggère que la machine virtuelle Java s'efforce pour recycler les objets inutilisés dans afin de rendre la mémoire qu'ils qu'ils occupent actuellement pour être rapidement réutilisation rapide. Lorsque le contrôle revient de l'appel de la l'appel de méthode, la machine virtuelle Java a fait de son mieux pour récupérer l'espace de tous les objets abandonnés.

6 votes

Cela oblige le Garbage Collector à fonctionner. Mais il ne le force pas à libérer de la mémoire...

14 votes

Non Pablo, cela ne force pas le GC à fonctionner.

0 votes

Merci, le premier paragraphe était à peu près ce que je voulais savoir. Merci d'avoir tout clarifié et oui, j'ai compris, je n'utiliserai pas System.gc() :)

69voto

Adamski Points 29884

Personne ne semble avoir mentionné le fait de mettre explicitement les références d'objets à null Il s'agit d'une technique légitime de "libération" de la mémoire que vous pouvez envisager.

Par exemple, disons que vous avez déclaré un List<String> au début d'une méthode, dont la taille a augmenté jusqu'à devenir très importante, mais qui n'a été nécessaire qu'à mi-parcours de la méthode. À ce stade, vous pouvez définir la référence de la liste à null pour permettre au ramasseur d'ordures de récupérer potentiellement cet objet avant que la méthode ne soit terminée (et la référence tombe hors de la portée de toute façon).

Notez que j'utilise rarement cette technique dans la réalité, mais elle vaut la peine d'être prise en compte lorsque l'on a affaire à de très grandes structures de données.

8 votes

Si vous travaillez vraiment beaucoup sur un objet qui n'est utilisé que pour une partie d'une méthode, je vous suggère soit que votre méthode est trop compilée, soit de la diviser en deux parties, avant et après, soit d'utiliser un bloc pour la première moitié du code (cette dernière option est plus utile pour les scripts de test).

6 votes

Il est important de mettre la référence d'un objet à null lorsqu'il est référencé à partir d'un autre objet à longue durée de vie (ou éventuellement à partir d'une variable statique). Par exemple, si vous avez un tableau d'objets de grande taille à durée de vie longue et que vous cessez d'utiliser l'un de ces objets, vous devez mettre la référence du tableau à null pour rendre l'objet disponible pour la GC.

23voto

Dean J Points 10987
System.gc(); 

Exécute le ramasseur de déchets.

Appel de la méthode gc suggère que la machine virtuelle Java s'efforce de recycler les objets inutilisés afin de rendre la mémoire qu'ils occupent disponible pour une réutilisation rapide. Lorsque le contrôle revient de l'appel de méthode, la machine virtuelle Java a fait de son mieux pour récupérer l'espace de tous les objets abandonnés.

Non recommandé.

Edit : J'ai écrit la réponse originale en 2009. Nous sommes maintenant en 2015.

Les collecteurs d'ordures se sont constamment améliorés au cours des 20 années d'existence de Java. À ce stade, si vous appelez manuellement le ramasseur de déchets, vous devriez envisager d'autres approches :

  • Si vous imposez la GC sur un nombre limité de machines, il peut être intéressant de faire appel à un équilibreur de charge. loin de la machine actuelle, en attendant qu'elle finisse de servir les clients connectés, qu'elle se termine après une certaine période pour les connexions en suspens, puis qu'elle redémarre tout simplement la JVM. C'est une solution terrible, mais si vous regardez System.gc(), les redémarrages forcés peuvent être un palliatif possible.
  • Envisagez d'utiliser un autre ramasseur de déchets. Par exemple, le collecteur G1 (nouveau au cours des six dernières années) est un modèle à faible pause ; il utilise globalement plus de CPU, mais fait de son mieux pour ne jamais forcer un arrêt brutal de l'exécution. Étant donné que les processeurs des serveurs ont maintenant presque tous plusieurs cœurs, c'est un très bon compromis à avoir.
  • Regardez vos drapeaux qui règlent l'utilisation de la mémoire. En particulier dans les nouvelles versions de Java, si vous n'avez pas beaucoup d'objets en cours d'exécution à long terme, pensez à augmenter la taille de newgen dans le tas. newgen (young) est l'endroit où les nouveaux objets sont alloués. Pour un serveur web, tout ce qui est créé pour une requête est placé ici, et si cet espace est trop petit, Java passera du temps supplémentaire à mettre à niveau les objets vers une mémoire à plus longue durée de vie, où il est plus coûteux de les tuer. (Si newgen est légèrement trop petit, vous allez le payer.) Par exemple, dans G1 :
    • XX:G1NewSizePercent (la valeur par défaut est 5 ; cela n'a probablement pas d'importance).
    • XX:G1MaxNewSizePercent (60 par défaut ; probablement augmenter cette valeur.)
  • Pensez à dire au collecteur de déchets que vous n'êtes pas d'accord avec une pause plus longue. Cela entraînera des passages plus fréquents du GC, pour permettre au système de conserver le reste de ses contraintes. En G1 :
    • XX:MaxGCPauseMillis (valeur par défaut : 200.)

1 votes

Pour en revenir à mon propre article, cela ne fait souvent rien, et l'appeler de façon répétée peut rendre la JVM instable et d'autres choses encore. Elle peut aussi écraser votre chien ; à approcher avec prudence.

1 votes

Je mettrais l'accent sur la partie "suggère" de "L'appel de la méthode gc suggère que la JVM développe ses efforts".

0 votes

Notez également qu'une seule invocation de System.gc() ne collecte généralement qu'un petit peu d'ordures. Pour tout collecter, vous devez l'invoquer dans une boucle, en utilisant la méthode suivante Runtime.freeMemory() pour surveiller le moment où la quantité de mémoire libre n'augmente plus. Mais appeler System.gc() est en effet rarement nécessaire. Un cas où c'est utile est lorsque vous essayez de mesurer la consommation de mémoire, car une exécution de la GC au milieu de cela va perturber vos mesures.

11voto

Dakkaron Points 492

*"Personnellement, je me fie à l'annulation des variables comme un substitut pour une suppression future appropriée. Par exemple, je prends le temps d'annuler tous les éléments d'un tableau avant de supprimer (rendre nul) le tableau lui-même."

C'est inutile. Ainsi, si j'ai un objet x avec une référence (=variable) a qui pointe vers lui, la GC ne le supprimera pas, car il existe une référence à cet objet :

a -> x

Si vous annulez un que cela se produit :

a -> null
     x

Donc maintenant x n'a pas de référence pointant vers lui et sera supprimé. La même chose se produit lorsque vous définissez a comme référence à un objet différent de x.

Ainsi, si vous avez un tableau arr qui fait référence aux objets x, y et z et une variable a qui fait référence au tableau, cela ressemble à cela :

a -> arr -> x
         -> y
         -> z

Si vous annulez un que cela se produit :

a -> null
     arr -> x
         -> y
         -> z

Donc, le GC trouve que arr n'a pas de référence et le supprime, ce qui donne cette structure :

a -> null
     x
     y
     z

Maintenant, le GC trouve x, y et z et les supprime également. Nuller chaque référence dans le tableau n'améliorera rien, cela ne fera qu'utiliser du temps CPU et de l'espace dans le code (ceci dit, cela ne fera pas plus mal que cela. Le GC sera toujours capable de fonctionner comme il le devrait).

5voto

Une raison valable pour vouloir libérer de la mémoire pour tout programme (java ou non) est de rendre plus de mémoire disponible pour d'autres programmes au niveau du système d'exploitation. Si mon application java utilise 250MB, je peux vouloir la forcer à descendre à 1MB et rendre les 249MB disponibles pour d'autres applications.

0 votes

Si vous devez explicitement libérer un morceau de 249 Mo, dans un programme Java, la gestion de la mémoire ne serait pas la première chose sur laquelle je voudrais travailler.

3 votes

Mais la libération de l'espace de stockage dans votre tas Java ne rend pas (dans le cas général) cet espace disponible pour les autres applications.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X