Pourquoi n'avez-vous pas explicitement appel finalize (), ou de lancer le garbage collector?

StackOverflow https://stackoverflow.com/questions/28949

  •  09-06-2019
  •  | 
  •  

Question

Après la lecture de cette question, Je me suis rappelé que lorsque j'avais appris Java et dit de ne jamais appeler finalize() ou d'exécuter le garbage collector parce que "c'est une grosse boîte noire que vous n'avez jamais besoin de s'inquiéter".Quelqu'un peut-il faire bouillir le raisonnement pour cela en quelques phrases?Je suis sûr que je pourrais lire un rapport technique de Soleil sur cette question, mais je pense que les une belle, courte, simple, la réponse devrait satisfaire ma curiosité.

Était-ce utile?

La solution

La réponse courte:Java la collecte des ordures est un très finement à l'écoute de l'outil.Système.gc() est une sledge-hammer.

Java heap est divisé en différentes générations, chaque de ce qui est recueilli à l'aide d'une stratégie différente.Si vous attachez un profiler pour une bonne application, vous verrez qu'il n'a que très rarement à courir le plus cher sortes de collections, car la plupart des objets sont pris par la copie plus rapide du collecteur dans la jeune génération.

Système D'Appel.gc() directement, même si, techniquement, il n'est pas garanti de faire quoi que ce soit, dans la pratique, sera le déclencheur d'un coûteux, cessez-le-monde plein de tas de collecte.C'est presque toujours la bonne chose à faire.Vous pensez que vous êtes économiser les ressources, mais vous êtes en train de perdre pour aucune bonne raison, forçant Java pour revérifier tous vos objets en direct “au cas où”.

Si vous rencontrez des problèmes avec le GC pauses lors des moments critiques, vous êtes mieux de la configuration de la JVM de l'utilisation simultanée de marque/sweep collecteur, qui a été spécialement conçu pour minimiser le temps passé en pause, que d'essayer de prendre une masse pour le problème et vient juste de tomber plus loin.

Le Soleil de document que vous pensiez de est ici: Java SE 6 HotSpot™ de la Machine Virtuelle de Collecte des Ordures Tuning

(Une autre chose que vous pourriez ne pas savoir:mise en œuvre d'une méthode finalize() de l'objet rend la collecte des ordures plus lent.Tout d'abord, il faudra deux GC fonctionne pour recueillir de l'objet:un pour courir finalize() et l'autre pour garantir que l'objet n'a pas été ressuscité au cours de finalisation.Deuxièmement, les objets avec finalize() les méthodes doivent être traités comme des cas particuliers par le GC, car ils doivent être collectées individuellement, ils ne peuvent simplement pas être jetés en vrac.)

Autres conseils

Ne vous embêtez pas avec les finaliseurs.

Commutateur à l'accroissement de la collecte des ordures.

Si vous voulez aider le garbage collector, null hors des références à des objets dont vous n'avez plus besoin.Moins de chemin à suivre= plus explicitement des ordures.

N'oubliez pas que (non statique) intérieure des instances de classe conserver les références de leurs parents instance de classe.Donc, un à l'intérieur de la classe thread conserve beaucoup plus de bagages que vous pourriez vous attendre.

Dans un très même ordre d'idées, si vous êtes en utilisant la sérialisation, et vous avez sérialisé objets temporaires, vous allez avoir besoin d'effacer la sérialisation des caches, en appelant ObjectOutputStream.reset() ou de votre processus de fuite de mémoire et finissent par mourir.Inconvénient est que les non-transitoire objets vont être à nouveau activé.La sérialisation temporaire d'objets de résultat peut être un peu plus salissant que vous ne le pensez!

Pensez à utiliser des références.Si vous ne savez pas ce soft références sont, avoir une lecture de la javadoc de java.lang.réf.SoftReference

Évitez les Fantômes des références et des références Faibles, sauf si vous avez vraiment obtenir excitables.

Enfin, si vous avez vraiment ne peut pas tolérer le GC utiliser en temps réel Java.

Non, je ne plaisante pas.

L'implémentation de référence est gratuit à télécharger et Peter Dibbles livre de SOLEIL est vraiment bonne lecture.

Aussi loin que les finaliseurs aller:

  1. Ils sont pratiquement inutiles.Ils ne sont pas garantis d'être appelé, en temps opportun, ou en effet, à tous (si la table n'est jamais à court, ni d'outils de finalisation).Cela signifie en général, vous ne devriez pas compter sur eux.
  2. Les finaliseurs ne sont pas garantis pour être idempotent.Le garbage collector prend le plus grand soin afin de garantir qu'il ne sera jamais appel finalize() plus d'une fois sur le même objet.Avec bien écrits, objets, il n'a pas d'importance, mais avec un mal écrit, les objets, l'appel de finaliser plusieurs fois peut causer des problèmes (p. ex.double sortie d'une ressource native ...crash).
  3. Chaque objet qui a une finalize() la méthode doit également fournir un close() (ou similaire) de la méthode.C'est la fonction à appeler.par exemple, FileInputStream.close().Il n'y a pas de raison de s'appeler finalize() lorsque vous avez une méthode plus appropriée que est destinée à être appelée par vous.

En supposant que les finaliseurs semblable à la leur .NET homonyme alors vous avez seulement besoin de les appeler lorsque vous avez des ressources telles que les descripteurs de fichiers qui peuvent fuite.La plupart du temps, vos objets n'ont pas ces références, ils n'ont pas besoin d'être appelé.

C'est mauvais pour essayer de collecter les ordures, car il n'est pas vraiment votre poubelle.Vous avez dit que la machine virtuelle pour allouer de la mémoire lorsque vous avez créé des objets, et que le garbage collector est pour cacher des informations à propos de ces objets.En interne, le GC est d'effectuer des optimisations sur les allocations de mémoire il fait.Lorsque vous essayer manuellement pour collecter les ordures, vous n'avez aucune connaissance de ce que le GC veut s'accrocher et de se débarrasser de, vous êtes juste forcer la main.Comme un résultat, vous vous trompez de calculs internes.

Si vous en savais plus sur ce que le GC a été tenue à l'interne, alors vous pourriez être en mesure de prendre des décisions plus éclairées, mais alors vous avez raté les avantages de la GC.

Le vrai problème avec la fermeture de l'OS gère à finaliser, c'est que le finaliser sont exécutées dans aucun ordre garanti.Mais si vous avez des poignées pour les choses qui bloquent (pensez par exempleles sockets), potentiellement, votre code peut obtenir en situation de blocage (pas trivial du tout).

Je suis donc explicitement poignées de fermeture prévisible et ordonnée.Fondamentalement code pour gérer les ressources devraient suivre le modèle:

SomeStream s = null;
...
try{
   s = openStream();
   ....
   s.io();
   ...
} finally {
   if (s != null) {
       s.close();
       s = null;
   }
}

Il devient encore plus compliqué si vous écrivez vos propres classes qui fonctionnent via JNI et les descripteurs ouverts.Vous devez vous assurer que les poignées sont fermés (publié) et qu'il va se passer qu'une seule fois.Souvent négligé OS poignée de Bureau J2SE est Graphics[2D].Même BufferedImage.getGrpahics() peut éventuellement vous retourner la poignée de points dans un pilote vidéo (en fait la tenue de la ressource sur GPU).Si vous ne relâchez pas vous-même et laisser garbage collector pour faire le travail, vous trouverez peut - être étrange OutOfMemory et comme situation quand vous avez manqué de carte vidéo mappé bitmaps mais ont encore beaucoup de mémoire.Dans mon expérience, il arrive assez fréquemment dans les boucles serrées travailler avec des objets graphiques (extraction de vignettes, de mise à l'échelle, la netteté de marque).

Fondamentalement GC ne prend pas soin de programmeurs responsabilité de la gestion correcte des ressources.Il ne s'occupe que de la mémoire, et rien d'autre.Le Flux De Données.finaliser l'appel à close() à mon humble avis serait mieux mis en œuvre jeter exception le nouveau RuntimeError("garbage collecte le flux est toujours ouverte").Il vous permettra d'économiser des heures et des jours de débogage et de nettoyage de code après la bâclée amateurs de gauche les extrémités perdre.

Heureux de codage.

La paix.

Le GC fait beaucoup de l'optimisation sur le moment de finaliser correctement les choses.

Donc, sauf si vous êtes familier avec la façon dont le GC fonctionne réellement et comment il les balises générations, manuellement l'appel de finaliser ou de démarrer GC require sera probablement nuire à la performance que de l'aide.

Éviter les finaliseurs.Il n'y a aucune garantie qu'ils seront appelés en temps opportun.Il pourrait prendre un temps assez long avant de la Gestion de la Mémoire système (c'est à dire, le garbage collector) décide de recueillir un objet avec un outil de finalisation.

Beaucoup de gens utilisent les finaliseurs de faire des choses comme fermer les connexions socket ou supprimer les fichiers temporaires.Ce faisant, vous faites votre demande au comportement imprévisible et attaché à quand la JVM va GC votre objet.Cela peut conduire à la "mémoire" des scénarios, pas en raison du Tas Java étant épuisé, mais plutôt en raison du système en cours d'exécution hors de poignées pour une ressource particulière.

Une autre chose à garder à l'esprit est que l'introduction d'appels Système.gc() ou ces marteaux peut montrer de bons résultats dans votre environnement, mais ils ne sont pas nécessairement à d'autres systèmes.Pas tout le monde fonctionne de la même JVM, il y a beaucoup, SUN, IBM J9, BEA JRockit, de l'Harmonie, OpenJDK, etc...Cette JVM sont tous conformes à la JCK (ceux qui ont été officiellement testé que c'est), mais qui ont beaucoup de liberté quand il s'agit de faire les choses rapidement.GC est l'une de ces zones, que tout le monde investit fortement.À l'aide d'un marteau va souvent de détruire que de l'effort.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top