Question

dit Effective Java:

  

Il y a une pénalité de performance sévère pour l'utilisation finaliseurs.

Pourquoi est-il plus lent de détruire un objet en utilisant les finaliseurs?

Était-ce utile?

La solution

En raison de la façon dont fonctionne le garbage collector. Pour les performances, la plupart Java GCS utilisent un collecteur copie, où sont attribués des objets de courte durée dans un bloc « eden » de la mémoire, et lorsque le il est temps pour cette génération d'objets à collecter, le GC a juste besoin de copier les objets sont encore « en vie » à un espace de stockage plus permanent, et il peut essuyer (gratuit) toute « eden » bloc de mémoire à la fois. Ceci est efficace parce que la plupart du code Java créera plusieurs milliers d'instances d'objets (primitives, tableaux temporaires en boîte, etc.) avec des durées de vie de seulement quelques secondes.

Lorsque vous avez finaliseurs dans le mélange, cependant, le GC ne peut pas simplement essuyer toute une génération à la fois. Au lieu de cela, il a besoin de comprendre tous les objets de cette génération qui ont besoin d'être mis au point, et les file d'attente sur un thread qui exécute réellement les finaliseurs. En attendant, le GC ne peut pas terminer le nettoyage des objets efficacement. Il a donc soit de les maintenir en vie plus longtemps qu'ils ne le devraient, ou il doit recueillir des retards des autres objets, ou les deux. De plus, vous avez le temps d'attente arbitraire d'exécuter effectivement les finaliseurs.

Tous ces facteurs contribuent à une pénalité d'exécution importante, ce qui explique pourquoi la finalisation déterministe (en utilisant une méthode de close() ou similaire pour finaliser explicitement l'état de l'objet)

est généralement préférée.

Autres conseils

Après avoir fait courir dans un tel problème:

Dans la machine virtuelle Java HotSpot Sun, finaliseurs sont traitées sur un fil qui est donné une priorité fixe, faible. Dans une application à forte charge, il est facile de créer des objets de finalisation-requis plus rapidement que le fil de mise au point faible priorité ne peut les traiter. Pendant ce temps, l'espace sur le tas utilisé par les objets de finalisation en attente est disponible pour d'autres utilisations. Finalement, votre application peut dépenser tout son ramassage des ordures de temps, parce que toute la mémoire disponible est utilisée par des objets en attente de finalisation.

Ceci est, bien sûr, en plus des autres nombreuses raisons de ne pas utiliser finaliseurs qui sont décrits dans Effective Java.

Je viens de prendre ma copie efficace Java de mon bureau pour voir ce qu'il parle.

Si vous lisez le chapitre 2, article 6, il va dans le bon détail sur les différents problèmes de performances.

You can't know when the finalizer will run, or even if it will at all. Because those resources may never be claimed, you will have to run with fewer resources.

Je recommande la lecture de l'intégralité de la section -. Il explique les choses beaucoup mieux que ce que je peux perroquet ici

Ma pensée est la suivante: Java est un langage de collecte des ordures, dont la mémoire de Libère basé sur ses propres algorithmes internes. Chaque si souvent, le GC scanne le tas, détermine les objets ne sont plus référencés, et de-alloue la mémoire. Un finaliseur interrompt cela et force la récupération mémoire en dehors du cycle de GC, ce qui pourrait causer des inefficacités. Je pense que les meilleures pratiques sont à utiliser finalizers qu'en cas de nécessité comme la libération de descripteurs de fichiers ou la fermeture des connexions DB qui doivent être faites de manière déterministe.

Si vous lisez la documentation de finalize () de près, vous remarquerez que les finaliseurs permettent un objet d'éviter d'être collectées par le GC.

Si aucun finaliseur est présent, il suffit de l'objet peut être retiré et n'a pas besoin de plus d'attention. Mais s'il y a un finaliseur, il doit être vérifié par la suite, si l'objet ne devienne pas « visible » à nouveau.

Sans savoir exactement comment la collecte des déchets en cours Java est mis en œuvre (en fait, parce qu'il ya différentes implémentations Java là-bas, il y a aussi différents GCS), vous pouvez supposer que le GC doit faire un travail supplémentaire si un objet a une finaliseur, en raison de cette fonction.

Une raison pour laquelle je peux penser est que le nettoyage de la mémoire explicite est inutile si vos ressources sont objets Java, et non du code natif.

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