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


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

Author: Felix, 2009-10-14

13 answers

Java utilise de la mémoire gérée, donc la seule façon d'allouer de la mémoire est d'utiliser l'opérateur new, et la seule façon de désallouer de la mémoire est de s'appuyer sur le garbage collector.

Ce 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 garbage collector s'exécute immédiatement. Cependant, le Runtime Java prend la décision finale, pas votre code.

Selon le Java documentation ,

Appeler la méthode gc suggère que la machine virtuelle Java dépense des efforts vers le recyclage des objets inutilisés dans afin de faire la mémoire ils actuellement occuper disponible pour rapide réutiliser. Lorsque le contrôle revient du appel de méthode, la Machine virtuelle Java a fait de son mieux pour récupérer espace de tous les objets mis au rebut.

 87
Author: Daniel Pryden, 2014-07-15 21:39:04

Personne ne semble avoir mentionné explicitement la définition de références d'objet à null, ce qui est une technique légitime pour "libérer" la mémoire que vous voudrez peut-être considérer.

Par exemple, supposons que vous ayez déclaré un List<String> au début d'une méthode dont la taille est devenue très grande, mais qui n'était requise que jusqu'à la moitié de la méthode. Vous pouvez à ce stade définir la référence de liste sur {[0] } pour permettre au garbage collector de récupérer potentiellement cet objet avant la fin de la méthode (et référence tombe de toute façon hors de portée).

Notez que j'utilise rarement cette technique en réalité, mais cela vaut la peine d'être pris en compte lorsque je traite de très grandes structures de données.

 58
Author: Adamski, 2009-10-14 19:50:13
System.gc(); 

Exécute le garbage collector.

L'appel de la méthode gc suggère que la machine virtuelle Java déploie des efforts pour recycler les objets inutilisés afin de rendre la mémoire qu'ils occupent actuellement disponible pour une réutilisation rapide. Lorsque control revient de l'appel de méthode, la machine virtuelle Java a fait de son mieux pour récupérer de l'espace à partir de tous les objets rejetés.

Non recommandé.

Edit: j'ai écrit la réponse originale dans 2009. C'est maintenant à 2015.

Les Garbage collectors se sont progressivement améliorés au cours des ~20 années d'existence de Java. À ce stade, si vous appelez manuellement le garbage collector, vous pouvez envisager d'autres approches:

  • Si vous forcez GC sur un nombre limité de machines, il peut être utile d'avoir un point d'équilibreur de charge éloigné de la machine actuelle, en attendant qu'elle finisse de servir aux clients connectés, délai d'attente après une certaine période pour suspendre les connexions, et puis redémarrez simplement la JVM. C'est une solution terrible, mais si vous regardez le système.gc (), les redémarrages forcés peuvent être un arrêt possible.
  • Envisagez d'utiliser un ramasse-miettes différent. Par exemple, le collecteur G1 (nouveau au cours des six dernières années) est un modèle à faible pause; il utilise plus de CPU dans l'ensemble, mais il est préférable de ne jamais forcer un arrêt brutal lors de l'exécution. Étant donné que les processeurs de serveur ont maintenant presque tous plusieurs cœurs, c'est un très Bon compromis à avoir disponible.
  • Regardez utilisation de la mémoire de réglage de vos drapeaux. Surtout dans les versions plus récentes de Java, si vous n'avez pas autant d'objets en cours d'exécution à long terme, envisagez d'augmenter la taille de newgen dans le tas. newgen (young) est l'endroit où de 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 plus de temps à mettre à niveau les objets vers une mémoire à plus longue durée de vie, où ils sont plus chers à tuer. (Si newgen est un peu trop petit, vous allez payer pour cela.) Par exemple, dans G1:
    • XX:G1NewSizePercent (la valeur par défaut est 5; cela n'a probablement pas d'importance.)
    • XX:G1MaxNewSizePercent (la valeur par défaut est 60; soulevez probablement cela.)
  • Pensez à dire au garbage collector que vous n'êtes pas d'accord avec une pause plus longue. Cela entraînera des exécutions GC plus fréquentes, pour permettre au système de conserver le reste de ses contraintes. En G1:
    • XX:MaxGCPauseMillis (la valeur par défaut est 200.)
 22
Author: Dean J, 2015-07-19 22:46:10

*"Personnellement, je compte sur l'annulation de variables comme espace réservé pour une future suppression 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."

Ce n'est pas nécessaire. La façon dont le GC Java fonctionne est qu'il trouve des objets qui n'ont aucune référence à eux, donc si j'ai un objet x avec une référence (=variable) a qui pointe vers lui, le GC ne le supprimera pas, car il y a une référence à cet objet:

a -> x

Si vous null a que cela arrive:

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 une référence à un objet différent de x.

Donc, 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 à ceci:

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

Si vous null a que cela se produit:

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

Donc le GC trouve arr comme n'ayant aucune référence définie et le supprime, ce qui vous donne ceci structure:

a -> null
     x
     y
     z

Maintenant, le GC trouve x, y et z et les supprime également. Annuler chaque référence dans le tableau ne fera rien de mieux, il utilisera simplement le temps CPU et l'espace dans le code (cela dit, cela ne fera pas de mal plus que cela. Le GC sera toujours en mesure d'effectuer la façon dont il devrait).

 11
Author: Dakkaron, 2014-01-25 20:28:26

Une raison valable de vouloir libérer de la mémoire de n'importe quel 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 250 Mo, je voudrai peut-être le forcer à 1 Mo et rendre le 249 Mo disponible pour d'autres applications.

 6
Author: Yios, 2012-03-27 08:18:27

J'ai fait des expérimentations à ce sujet.

Il est vrai que System.gc(); suggère seulement d'exécuter le Garbage Collector.

Mais appeler System.gc(); après avoir défini toutes les références à null, améliorera les performances et l'occupation de la mémoire.

 5
Author: Hemant Yadav, 2018-03-27 23:27:50

Pour prolonger la réponse et le commentaire de Yiannis Xanthopoulos et Hot Licks (désolé, je ne peux pas encore commenter!), vous pouvez définir des options de machine virtuelle comme cet exemple:

-XX:+UseG1GC -XX:MinHeapFreeRatio=15 -XX:MaxHeapFreeRatio=30

Dans mon jdk 7, cela libérera alors la mémoire VM inutilisée si plus de 30% du tas devient libre après GC lorsque la VM est inactive. Vous devrez probablement régler ces paramètres.

Bien que je ne l'ai pas vu souligné dans le lien ci-dessous, notez que certains garbage collectors peuvent ne pas obéir à ces paramètres et par défaut java peut choisissez l'un d'entre eux pour vous, si vous avez plus d'un noyau (d'où l'argument UseG1GC ci-dessus).

Arguments de machine virtuelle

Mise à jour: Pour java 1.8.0_73, j'ai vu la JVM libérer occasionnellement de petites quantités avec les paramètres par défaut. Semble ne le faire que si ~70% du tas est inutilisé.. je ne sais pas si ce serait plus agressif de libérer si le système d'exploitation était faible en mémoire physique.

 4
Author: nsandersen, 2017-01-12 14:12:34

Si vous voulez vraiment allouer et libérer un bloc de mémoire, vous pouvez le faire avec des ByteBuffers directs. Il existe même un moyen non portable de libérer la mémoire.

Cependant, comme cela a été suggéré, ce n'est pas parce que vous devez libérer de la mémoire en C que cela signifie une bonne idée de devoir le faire.

Si vous sentez que vous avez vraiment un bon cas d'utilisation pour free(), veuillez l'inclure dans la question afin que nous puissions voir ce que vous essayez de faire, il est fort probable qu'il existe un meilleur moyen.

 3
Author: Peter Lawrey, 2010-07-13 20:11:08

Entièrement à partir de javacoffeebreak.com/faq/faq0012.html

Un thread à faible priorité s'occupe automatiquement de la collecte des ordures pour l'utilisateur. Pendant la période d'inactivité, le fil peut être appelé, et il peut commencer à libérer de la mémoire précédemment allouée à un objet en Java. Mais ne vous inquiétez pas - il ne supprimera pas vos objets sur vous!

Lorsqu'il n'y a pas de références à un objet, cela devient un jeu équitable pour le garbage collector. Plutôt que d'appeler une routine (gratuit dans C++), vous assignez simplement toutes les références à l'objet à null, ou attribuer une nouvelle classe à la référence.

Exemple :

public static void main(String args[])
{
  // Instantiate a large memory using class
  MyLargeMemoryUsingClass myClass = new MyLargeMemoryUsingClass(8192);

  // Do some work
  for ( .............. )
  {
      // Do some processing on myClass
  }

  // Clear reference to myClass
  myClass = null;

  // Continue processing, safe in the knowledge
  // that the garbage collector will reclaim myClass
}

Si votre code est sur le point de demander une grande quantité de mémoire, vous pouvez vous voulez demander au garbage collector de commencer à récupérer de l'espace, plutôt que lui permettant de faire un thread de priorité faible. Pour ce faire, ajoutez ce qui suit à votre code

System.gc();

Le garbage collector tentera de récupérer de l'espace libre, et votre l'application peut continuer à s'exécuter, avec autant de mémoire récupérée que possible (des problèmes de fragmentation de la mémoire peuvent s'appliquer sur certaines plates-formes).

 2
Author: Stefan Falk, 2015-04-20 08:57:42

Dans mon cas, puisque mon code Java est destiné à être porté vers d'autres langages dans un proche avenir (principalement C++), je veux au moins payer du bout des lèvres pour libérer correctement la mémoire afin que cela aide le processus de portage plus tard.

Personnellement, je compte sur l'annulation de variables comme espace réservé pour une future suppression 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.

Mais mon cas est très particulier, et je sais que je prends la performance frappe lorsque vous faites cela.

 1
Author: Oskuro, 2012-07-27 11:39:46

* "Par exemple, supposons que vous ayez déclaré une liste au début d'un méthode qui a grandi en taille pour être très grande, mais était seulement nécessaire jusqu'à mi-chemin par le biais de la méthode. Vous pouvez à ce stade définir le Liste référence à null pour permettre au garbage collector de potentiellement récupérez cet objet avant la fin de la méthode (et la référence tombe de toute façon hors de portée)." *

C'est correct, mais cette solution peut ne pas être généralisables. Lors de la définition d'une référence d'objet de liste à null-will-make memory available for garbage collection, ceci n'est vrai que pour un objet List de types primitifs. Si l'objet List contient plutôt des types de référence, la définition de List object = null ne déréférencera aucun des types de référence contenus dans la liste. Dans ce cas, la définition de la Liste object = null orphelin les types de référence contenus dont les objets ne seront pas disponibles pour la collecte de déchets à moins que l'algorithme de collecte de déchets est assez intelligent pour déterminer que le les objets sont devenus orphelins.

 1
Author: Gothri, 2012-08-31 21:11:00

Bien que java fournisse une récupération de place automatique, vous voudrez parfois savoir quelle est la taille de l'objet et combien il en reste .Mémoire libre en utilisant par programme import java.lang; et Runtime r=Runtime.getRuntime(); pour obtenir des valeurs de mémoire en utilisant mem1=r.freeMemory(); pour libérer la mémoire appelez la méthode r.gc(); et l'appel freeMemory()

 1
Author: Benjamin, 2014-09-25 05:18:38

La recommandation de JAVA est d'assigner à null

À Partir de https://docs.oracle.com/cd/E19159-01/819-3681/abebi/index.html

L'attribution explicite d'une valeur null à des variables qui ne sont plus nécessaires aide le garbage collector à identifier les parties de mémoire pouvant être récupérées en toute sécurité. Bien que Java fournisse une gestion de la mémoire, il n'empêche pas les fuites de mémoire ou l'utilisation de quantités excessives de mémoire.

Une application peut induire des fuites de mémoire en ne libération des références d'objet. Cela empêche le Garbage collector Java de récupérer ces objets et entraîne une augmentation de la quantité de mémoire utilisée. L'annulation explicite des références aux variables après leur utilisation permet au garbage collector de récupérer de la mémoire.

Une façon de détecter les fuites de mémoire consiste à utiliser des outils de profilage et à prendre des instantanés de mémoire après chaque transaction. Une application sans fuite en état stationnaire affichera une mémoire de tas active constante après la poubelle collection.

 1
Author: user3869837, 2018-04-11 16:24:54