web-dev-qa-db-fra.com

Quand System.gc () fait-il quelque chose?

Je sais que la récupération de place est automatisée en Java. Mais j’ai compris que si vous appelez System.gc() dans votre code, la machine virtuelle Java peut décider ou non d’effectuer la récupération de place à ce stade. Comment cela fonctionne-t-il précisément? Sur quelle base/quels paramètres la JVM décide-t-elle de faire (ou de ne pas faire) un GC quand elle voit System.gc()?

Existe-t-il des exemples dans lesquels il est judicieux de mettre cela dans votre code?

111
harry

En pratique, il décide généralement de faire un ramassage des ordures. La réponse varie en fonction de nombreux facteurs, tels que la machine virtuelle Java sur laquelle vous exécutez, le mode dans lequel elle s'exécute et l'algorithme de récupération de place utilisé.

Je ne dépendrais pas de cela dans votre code. Si la machine virtuelle Java est sur le point de générer une erreur OutOfMemoryError, l'appel à System.gc () ne l'arrêtera pas, car le récupérateur de mémoire tentera de libérer autant qu'il le peut avant de passer à l'extrême. La seule fois que je l'ai vu utilisé dans la pratique, c'est dans les IDE où il est attaché à un bouton sur lequel l'utilisateur peut cliquer, mais même là, ce n'est pas très utile.

58
jodonnell

Le seul exemple auquel je puisse penser où il est logique d'appeler System.gc () concerne le profilage d'une application pour rechercher d'éventuelles fuites de mémoire. Je crois que les profileurs appellent cette méthode juste avant de prendre un instantané de la mémoire.

29

La spécification de langage Java ne garantit pas que la machine virtuelle Java démarrera un GC lorsque vous appelez System.gc().). C’est la raison de cette "peut décider ou non de faire un GC. à ce moment".

Maintenant, si vous regardez code source OpenJDK , qui est l’épine dorsale de la JVM Oracle, vous verrez qu’un appel à System.gc() commence un cycle de GC. Si vous utilisez une autre machine virtuelle, telle que J9, vous devez consulter leur documentation pour trouver la réponse. Par exemple, la machine virtuelle Java d'Azul dispose d'un collecteur de mémoire qui fonctionne en permanence, de sorte qu'un appel à System.gc() ne fera rien.

Une autre réponse mentionne le démarrage d'un GC dans JConsole ou VisualVM. Fondamentalement, ces outils effectuent un appel à distance à System.gc().

Généralement, vous ne souhaitez pas démarrer un cycle de récupération de place à partir de votre code, car il gâche la sémantique de votre application. Votre application effectue des tâches professionnelles, la JVM s’occupe de la gestion de la mémoire. Vous devez garder ces préoccupations séparées (ne faites pas que votre application gère la mémoire, concentrez-vous sur les affaires).

Cependant, il existe peu de cas où un appel à System.gc() pourrait être compréhensible. Considérons, par exemple, les micro-repères. Personne ne veut qu'un cycle de GC se produise au milieu d'une micro-référence. Vous pouvez donc déclencher un cycle GC entre chaque mesure pour vous assurer que chaque mesure commence par un segment vide.

24
Pierre Laporte

Vous n'avez aucun contrôle sur GC dans Java - la VM décide. Je n'ai jamais rencontré un cas où System.gc() est nécessaire . Comme un appel de System.gc() suggère simplement que VM effectue un ramassage des ordures et effectue également un ramassage des déchets PLEIN (anciennes et nouvelles générations dans un segment de mémoire multigénérationnel), cause [~ # ~] plus [~ # ~] cycles CPU à consommer que nécessaire.

Dans certains cas, il peut être judicieux de suggérer au VM d'effectuer une collecte complète MAINTENANT, car vous savez peut-être que l'application restera inactive pendant les prochaines minutes avant que des opérations de levage lourdes ne se produisent. Par exemple, juste après l’initialisation d’un grand nombre d’objets temporaires lors du démarrage de l’application (c’est-à-dire que je viens de mettre en cache une tonne d’informations et que je sais que je n’aurai pas beaucoup d’activité pendant une minute ou deux). Pensez à un IDE tel que le démarrage d'Eclipse - l'initialisation est importante. Il est donc peut-être logique de procéder immédiatement après l'initialisation à un gc complet à ce stade.

23
DustinB

Vous devez faire très attention si vous appelez System.gc(). L'appeler peut ajouter des problèmes de performances inutiles à votre application, et il n'est pas garanti qu'il effectue réellement une collection. Il est en fait possible de désactiver explicitement System.gc() via l'argument Java argument -XX:+DisableExplicitGC.

Je vous recommande vivement de lire les documents disponibles sur le site Java HotSpot Garbage Collection pour des informations plus détaillées sur le garbage collection.

17
David Schlosnagle

System.gc() est implémenté par la machine virtuelle et est spécifique à cette implémentation. Le responsable de la mise en œuvre pourrait simplement revenir et ne rien faire, par exemple.

En ce qui concerne le moment où une collecte manuelle doit être effectuée, la seule fois où vous souhaiterez le faire, c’est lorsque vous abandonnerez une collection volumineuse contenant des charges de collections plus petites - un Map<String,<LinkedList>> _ par exemple - et vous voulez tenter votre chance, mais vous ne devriez surtout pas vous en inquiéter. Le GC le sait mieux que vous - malheureusement - la plupart du temps.

10
Patrick

Si vous utilisez des mémoires tampons directes, la machine virtuelle Java n'exécute pas le GC, même si vous manquez de mémoire directe.

Si vous appelez ByteBuffer.allocateDirect() et que vous obtenez une erreur OutOfMemoryError, vous constaterez que cet appel convient parfaitement après le déclenchement manuel d'un CPG.

8
Peter Lawrey

La plupart des machines virtuelles lancent un CPG (en fonction des commutateurs -XX: DiableExplicitGC et -XX: + ExplicitGCInvokesConcurrent). Mais la spécification est juste moins bien définie afin de permettre de meilleures implémentations plus tard.

La spécification nécessite des éclaircissements: Bogue n ° 6668279: (spec), System.gc () devrait indiquer que nous déconseillons l'utilisation et que nous ne garantissons pas le comportement

En interne, la méthode gc est utilisée par RMI et NIO et nécessite une exécution synchrone qui: ceci est en cours de discussion:

Bug n ° 5025281: autorisait System.gc () à déclencher des collections complètes simultanées (et non à l'arrêt du monde)

5
eckes

Garbage Collection Est bon dans Java, si nous exécutons un logiciel codé dans Java dans un ordinateur de bureau/un ordinateur portable/un serveur. Vous pouvez appeler System.gc() ou Runtime.getRuntime().gc() dans Java.

Notez simplement qu'aucun de ces appels n'est garanti pour faire quoi que ce soit. Ils sont juste une suggestion pour que le JVM exécute le ramasse-miettes. C'est à la JVM qu'elle exécute le GC ou non. Donc, réponse courte: nous ne savons pas quand cela fonctionne. Réponse plus longue: JVM exécuterait gc s'il en avait le temps.

Je crois que la même chose s'applique pour Android. Cependant, cela pourrait ralentir votre système.

2
Naveen

Normalement, VM effectue automatiquement un nettoyage de la mémoire avant de lancer une exception OutOfMemoryException. Par conséquent, l'ajout d'un appel explicite ne devrait pas vous aider, sauf qu'il déplace peut-être l'impact sur les performances à un moment antérieur.

Cependant, je pense avoir rencontré un cas où cela pourrait être pertinent. Je ne suis toutefois pas sûr, car je n'ai pas encore vérifié si cela a un effet:

Lorsque vous mappez un fichier en mémoire, je crois que l'appel map () lève une exception IOException lorsqu'un bloc de mémoire suffisamment volumineux n'est pas disponible. Une récupération de place juste avant le fichier map () pourrait aider à empêcher cela, je pense. Qu'est-ce que tu penses?

2
Vashek

nous ne pouvons jamais forcer le ramassage des ordures. System.gc ne fait que suggérer que vm pour le ramassage des ordures. Cependant, personne ne sait vraiment à quelle heure le mécanisme fonctionne, c'est ce qui est indiqué dans les spécifications JSR.

2
lwpro2

Il y a BEAUCOUP à dire en prenant le temps de tester les divers paramètres de récupération de place, mais comme cela a été mentionné ci-dessus, il n'est généralement pas utile de le faire.

Je travaille actuellement sur un projet impliquant un environnement limité en mémoire et des quantités de données relativement importantes. Quelques données volumineuses poussent mon environnement à la limite, et même si j'ai pu réduire l'utilisation de la mémoire, qu'en théorie cela fonctionnerait très bien, j'aurais quand même des erreurs de tas d'espace --- les options de GC verbeuses m'ont montré qu'il essayait de ramasser des ordures, mais en vain. Dans le débogueur, je pouvais exécuter System.gc () et bien sûr, il y aurait "beaucoup" de mémoire disponible ... pas beaucoup d'extra, mais assez.

Par conséquent, le seul moment où mon application appelle System.gc () est le moment où il est sur le point d'entrer le segment de code où les tampons volumineux nécessaires au traitement des données seront alloués, et un test de la mémoire disponible indique que je ne suis pas connecté. garanti de l'avoir. En particulier, je cherche un environnement de 1 Go où au moins 300 Mo sont occupés par des données statiques, la majeure partie des données non statiques étant liée à l'exécution, sauf lorsque les données en cours de traitement sont d'au moins 100-200 Mo à la source. Tout cela fait partie d'un processus de conversion automatique des données. Par conséquent, les données existent toutes pour des périodes relativement courtes à long terme.

Malheureusement, bien que des informations sur les différentes options de réglage du ramasse-miettes soient disponibles, il semble qu’il s’agisse en grande partie d’un processus expérimental et les spécificités de niveau inférieur nécessaires pour comprendre comment gérer ces situations spécifiques ne sont pas faciles à obtenir.

Cela étant dit, même si j'utilise System.gc (), j'ai quand même continué à ajuster en utilisant des paramètres de ligne de commande et j'ai réussi à améliorer le temps de traitement global de mon application d'une quantité relativement importante, même si je ne pouvais pas dépasser problème rencontré en travaillant avec les plus gros blocs de données. Ceci étant dit, System.gc () est un outil ... très peu fiable, et si vous ne faites pas attention à la façon dont vous l'utilisez, vous souhaiterez qu'il ne fonctionne pas plus souvent.

2
Kyune

En bref:

Les paramètres sont VM dépendant.

Exemple d'utilisation - je ne peux pas en penser un pour les applications d'exécution/de production, mais il est utile de l'exécuter pour certains faisceaux de profilage, comme les appels

// test run #1
test();
for (int i=0; i<10; i++) { 
// calling repeatedly to increase chances of a clean-up
  System.gc(); 
}
// test run #2
test();
1
mataal

Si vous voulez savoir si votre System.gc() est appelée, vous pouvez, avec le nouveau Java 7 mise à jour 4 obtenir une notification lorsque la JVM effectue un nettoyage de la mémoire.

Je ne suis pas sûr à 100% que la classe GarbageCollectorMXBean ait été introduite dans Java 7 mise à jour 4, car je ne pouvais pas la trouver dans les notes de publication, mais j'ai trouvé les informations sur le site javaperformancetuning . com

1
Shervin Asgari

Selon Thinking in Java de Bruce Eckel, un cas d'utilisation d'un appel explicite System.gc () est celui où vous souhaitez forcer la finalisation, dans l'appel à - finaliser méthode.

0
Asterisk

Je ne peux pas penser à un exemple spécifique quand il est bon de lancer un GC explicite.

En général, exécuter GC explicite peut en réalité causer plus de tort que de bien, car un gc explicite déclenchera une collection complète, ce qui prendra beaucoup plus de temps à travers chaque objet. Si ce gc explicite finit par être appelé à plusieurs reprises, cela pourrait facilement conduire à une application lente car beaucoup de temps est consacré à l'exécution de CPG complets.

Alternativement, si vous passez en revue le tas avec un analyseur de tas et que vous suspectez un composant de la bibliothèque d'appeler des GC explicites, vous pouvez le désactiver en ajoutant: gc = -XX: + DisableExplicitGC aux paramètres de la machine virtuelle Java.

0
zxcv

bien que system.gc fonctionne, il arrêtera le monde: tous les réponses seront arrêtées afin que Garbage Collector puisse analyser chaque objet pour vérifier s'il est nécessaire de le supprimer. si l'application est un projet Web, toutes les demandes sont arrêtées jusqu'à la fin de la commande gc, ce qui empêchera votre projet Web de fonctionner de manière instantanée.

0
fleture