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 Définir l'objet sur null et compter sur GC est-il la seule option?
13 réponses
Java utilise 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 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 ,
L'appel de la méthode gc suggère que la machine virtuelle Java dépenser des efforts vers le recyclage des objets inutilisés dans afin de rendre la mémoire ils occupe actuellement disponible pour rapide réutiliser. Lorsque le contrôle revient du appel de méthode, la machine virtuelle Java a fait le meilleur effort pour récupérer espace de tous les objets mis au rebut.
Personne ne semble avoir mentionné explicitement la définition de références d'objets à null
, ce qui est une technique légitime pour "libérer" la mémoire que vous voudrez peut-être considérer.
Par exemple, disons que vous avez déclaré un List<String>
au début d'une méthode qui a grandi en taille pour être très grande, mais n'a été requise qu'à mi-chemin de la méthode. Vous pouvez à ce stade définir la référence de la liste sur null
pour permettre au garbage collector de récupérer potentiellement cet objet avant la fin de la méthode (et le référence tombe hors de portée de toute façon).
Notez que j'utilise rarement cette technique en réalité, mais cela vaut la peine d'être pris en compte lorsqu'il s'agit de très grandes structures de données.
System.gc();
Exécute le garbage collector.
L'appel de la méthode gc suggère que la Machine virtuelle Java dépense 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 le contrôle 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. Nous sommes maintenant en 2015.
Les garbage collectors se sont progressivement améliorés au cours des 20 années que Java a connues. À 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'équilibrage 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 juste dur-redémarrez 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.
- pensez à utiliser un autre garbage collector. Par exemple, le (nouveau au cours des six dernières années) G1 collector 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 difficile à l'exécution. Puisque les processeurs serveur ont maintenant presque tous plusieurs cœurs, c'est un très bon compromis à avoir.
- regardez vos drapeaux, paramétrage utilisation de la mémoire. Surtout dans les versions plus récentes de Java, si vous n'avez pas autant d'objets en cours d'exécution à long terme, pensez à 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 mis ici, et si cet espace est trop petit, Java passera plus de temps à mettre à niveau les objets vers une mémoire plus longue, où ils sont plus chers à tuer. (Si newgen est un peu trop petit, vous allez payer pour cela.) Par exemple, dans G1:
- XX: G1NewSizePercent (par défaut à 5; n'a probablement pas d'importance.)
- XX: G1MaxNewSizePercent (par défaut à 60; probablement augmenter 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 garder le reste de ses contraintes. En G1:
- XX: MaxGCPauseMillis (par défaut 200.)
* " personnellement, je compte sur les variables nulling comme un espace réservé pour la future suppression correcte. Par exemple, je prends le temps d'annuler tous les éléments d'un tableau avant de supprimer (en faisant null) 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 se produit:
a -> null
x
Alors maintenant x n'a pas de référence pointant vers elle et sera supprimé. La même chose se produit lorsque vous définissez a pour faire 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 aussi. Annuler chaque référence dans le tableau ne fera rien de mieux, il utilisera simplement le temps et l'espace CPU dans le code (cela dit, cela ne fera pas de mal plus loin que cela. Le GC sera toujours en mesure d'effectuer la façon dont il devrait).
Une raison valable pour 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 250MB, je peux le forcer à 1MB et rendre le 249MB disponible pour d'autres applications.
J'ai fait des expériences à 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.
Pour étendre sur 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 VM comme cet exemple:
-XX:+UseG1GC -XX:MinHeapFreeRatio=15 -XX:MaxHeapFreeRatio=30
Dans mon jdk 7, cela libérera ensuite la mémoire VM inutilisée si plus de 30% du tas devient libre après GC lorsque la VM est inactive. Vous aurez probablement besoin de 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).
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 si le système d'exploitation était faible en mémoire physique.
Si vous voulez vraiment allouer et libérer un bloc de mémoire, vous pouvez le faire avec Direct ByteBuffers. Il existe même un moyen non portable de libérer la mémoire.
Cependant, comme cela a été suggéré, juste parce que vous devez libérer de la mémoire en C, ne signifie pas que c'est une bonne idée d'avoir à 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 y ait un meilleur moyen.
Entièrement à partir de javacoffeebreak.com/faq/faq0012.html
Un thread à faible priorité s'occupe automatiquement de la récupération 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!
Quand 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 voulez-vous 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 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).
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 rendre hommage à libérer correctement la mémoire afin d'aider le processus de portage plus tard.
Personnellement, je compte sur les variables nulling comme un espace réservé pour la future suppression correcte. Par exemple, je prends le temps d'annuler tous les éléments d'un tableau avant de supprimer (en faisant null) le tableau lui-même.
Mais mon cas est très particulier, et je sais que je prends la performance frappe en faisant cela.
* "par exemple, disons que vous avez 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 des références à null pour permettre au garbage collector de récupérer cet objet avant la fin de la méthode (et la référence est hors de portée de toute façon)." *
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 -va - faire de la mémoire disponible pour la collecte des ordures, ce n'est vrai que pour un objet de Liste de types primitifs. Si l'objet List contient à la place des types de référence, la définition de L'objet List = null ne déréférencera aucun des types de référence contenus dans la liste. Dans ce cas, la définition de List object = null orphelinera les types de référence contenus dont les objets ne seront pas disponibles pour la récupération de place à moins que l'algorithme de récupération de place soit suffisamment intelligent pour déterminer que le les objets ont été orphelins.
Althrough java fournit la collecte automatique des ordures parfois, vous voudrez savoir quelle est la taille de l'objet et combien il reste .Mémoire libre en utilisant par programmation import java.lang;
et Runtime r=Runtime.getRuntime();
pour obtenir des valeurs de mémoire en utilisant mem1=r.freeMemory();
pour libérer de la mémoire appelez la méthode r.gc();
et l'appel freeMemory()
La recommandation de JAVA est d'attribuer à 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 la mémoire qui peuvent être récupérées en toute sécurité. Bien que Java assure la 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 libérer des références d'objets. 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. Annuler explicitement les 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 est d'utiliser des outils de profilage et de prendre des instantanés de mémoire après chaque transaction. Une application sans fuite en état d'équilibre affichera une mémoire de tas active stable après la poubelle collection.