Existe-t-il un moyen de libérer de la mémoire en Java, similaire à la free()
fonction C ? Ou est-ce que définir l'objet sur null et s'appuyer sur GC est la seule option?
Existe-t-il un moyen de libérer de la mémoire en Java, similaire à la free()
fonction C ? Ou est-ce que définir l'objet sur null et s'appuyer sur GC est la seule option?
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' new
opérateur, 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 vous 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, c'est le Java Runtime qui prend la décision finale, pas votre code.
Selon la documentation Java ,
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 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 sur tous les objets ignorés.
System.gc()
totalement.
Personne ne semble avoir mentionné explicitement la définition de références aux objets null
, ce qui est une technique légitime pour «libérer» la mémoire que vous voudrez peut-être envisager.
Par exemple, supposons que vous ayez déclaré un List<String>
au début d'une méthode dont la taille a augmenté pour devenir très grande, mais qui n'a été nécessaire que jusqu'à la moitié de la méthode. Vous pouvez à ce stade définir la référence List sur null
pour permettre au garbage collector de récupérer potentiellement cet objet avant que la méthode ne se termine (et la 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 vous traitez 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é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 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 sur tous les objets ignorés.
Non recommandé.
Edit: J'ai écrit la réponse originale en 2009. Nous sommes maintenant en 2015.
Les éboueurs se sont régulièrement améliorés au cours des ~ 20 ans d'existence de Java. À ce stade, si vous appelez manuellement le garbage collector, vous pouvez envisager d'autres approches:
* "Personnellement, je compte sur l'annulation des variables comme espace réservé pour une future suppression correcte. 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."
Ceci est inutile. 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 Object 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 lui 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 à ça:
a -> arr -> x
-> y
-> z
Si vous null a que cela se produit:
a -> null
arr -> x
-> y
-> z
Ainsi, le GC trouve arr comme n'ayant aucune référence définie et le supprime, ce qui vous donne cette 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, cela utilisera simplement du temps CPU et de l'espace dans le code (cela dit, cela ne fera pas mal plus que cela. Le GC sera toujours en mesure de fonctionner comme il le devrait. ).
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 peux le forcer à 1 Mo et rendre le 249 Mo disponible pour d'autres applications.
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 les options de la VM comme cet exemple:
-XX:+UseG1GC -XX:MinHeapFreeRatio=15 -XX:MaxHeapFreeRatio=30
Dans mon jdk 7, cela libèrera alors la mémoire de la 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 collector peuvent ne pas obéir à ces paramètres et que par défaut, java peut en choisir un pour vous, si vous avez plus d'un cœur (d'où l'argument UseG1GC ci-dessus ).
Mise à jour: Pour java 1.8.0_73, j'ai vu la JVM publier occasionnellement de petites quantités avec les paramètres par défaut. Semble ne le faire que si ~ 70% du tas est inutilisé cependant ... je ne sais pas si la libération serait plus agressive si le système d'exploitation manquait de mémoire physique.
J'ai fait des expériences à ce sujet.
Il est vrai que cela System.gc();
suggère uniquement 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.
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 de 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 vous devez le faire.
Si vous pensez que vous avez vraiment un bon cas d'utilisation gratuit (), veuillez l'inclure dans la question afin que nous puissions voir ce que vous voulez faire, il est fort probable qu'il existe un meilleur moyen.
Entièrement à partir de javacoffeebreak.com/faq/faq0012.html
Un thread de faible priorité prend en charge automatiquement le garbage collection pour l'utilisateur. Pendant le temps d'inactivité, le thread 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 - cela ne supprimera pas vos objets sur vous!
Lorsqu'il n'y a aucune référence à un objet, cela devient un jeu équitable pour le ramasse-miettes. Plutôt que d'appeler une routine (comme free en C ++), vous affectez simplement toutes les références à l'objet à null, ou affectez 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 souhaiterez peut-être demander au garbage collector de commencer à récupérer de l'espace, plutôt que de lui permettre de le faire en tant que thread de faible priorité. 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 application pourra 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, étant donné que mon code Java est destiné à être porté dans 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 facilite le processus de portage plus tard.
Je compte personnellement sur l'annulation des 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 des performances en faisant cela.
* "Par exemple, supposons que vous ayez déclaré une liste au début d'une méthode dont la taille est devenue très grande, mais qui n'a été requise que jusqu'à la moitié de la méthode. Vous pouvez à ce stade définir la référence de liste sur null pour permettre au garbage collector de récupérer potentiellement cet objet avant que la méthode ne se termine (et que 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éralisable. Lors de la définition d'une référence d'objet List sur null - rendra la mémoire disponible pour le garbage collection, cela n'est vrai que pour un objet List 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 l'objet List = null rendra orphelins les types de référence contenus dont les objets ne seront pas disponibles pour le garbage collection à moins que l'algorithme de garbage collection ne soit suffisamment intelligent pour déterminer que les objets sont orphelins.
Althrough java fournit la collecte des ordures automatique parfois vous voulez savoir la taille de l'objet est et combien il est laissé mémoire à l' aide .Gratuit programatically import java.lang;
et Runtime r=Runtime.getRuntime();
pour obtenir des valeurs de mémoire à l' aide mem1=r.freeMemory();
d'appel de mémoire libre de la r.gc();
méthode et l'appelfreeMemory()
La recommandation de JAVA est d'assigner à null
Depuis https://docs.oracle.com/cd/E19159-01/819-3681/abebi/index.html
L'affectation explicite d'une valeur nulle à des variables qui ne sont plus nécessaires aide le garbage collector à identifier les parties de 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 provoquer des fuites de mémoire en ne libérant pas de 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 stable affichera une mémoire de tas active stable après les garbage collection.