Chasse aux memory leaks, VisualVM: «Aucune racine GC trouvée». Et après?

J’ai un vidage de mémoire que j’ai fait à partir d’une application mourante. Il a consommé tout le tas disponible (-Xmx1024m). Il utilise com.gargoylesoftware.htmlunit.WebClient pour parsingr les pages Web. Effectue quelques requêtes http à la minute, meurt en plusieurs jours. Comme je vois dans le dump, il contient environ 1750 instances de la classe HtmlPage , chacune contenant des tons d’objects associés, y compris le contenu intégral d’une page analysée.

Je ne comprends pas pourquoi les HtmlPage ne sont pas récupérées. J’ai examiné les références d’instance et je ne vois aucun code contenant une référence. VisualVM dit “Aucune racine GC n’a été trouvée”. Si j’ai bien compris, cela devrait signifier que l’object est éligible pour gc, mais cela ne fonctionne pas.

L’application s’exécute comme un processus autonome simple, elle n’utilise aucun conteneur Web ni serveur d’applications.

Des allusions? Que devrais-je examiner?

Spécifications:

  • htmlunit v2.7
  • Version Java “1.6.0_13” Environnement d’exécution Java SE (version 1.6.0_13-b03) VM HotSpot (TM) Server (version 11.3-b02, mode mixte)
  • Linux my.lan 2.6.18-128.el5 # 1 SMP mer 17 déc 11:42:39 EST 2008 i686 i686 i386 GNU / Linux

Update1

J’ai essayé d’parsingr le dump par YourKit Java Profiler. Il me montre beaucoup d’objects java.lang.ref.Finalizer avec 310 Mo de taille conservée. Ils sont créés pour le net.sourceforge.htmlunit.corejs.javascript.NativeGenerator#finalize() , et NativeGenerator fait référence à Window , puis à HtmlPage et à tout le HtmlPage .

Est-ce que quelqu’un sait pourquoi restnt-ils en mémoire?

Remarque : Curieux, mais VisualVM affiche “En attente de finalisation” à zéro.

Assurez-vous d’appeler webClient.closeAllWindows () une fois que vous avez terminé avec la (les) page (s) – sinon le fil JavaScript continue de fonctionner en conservant des références contenant les ressources de la page, etc.

Lorsqu’un object a une méthode finalize () non sortingviale, lors de la création d’une instance de l’object, la machine virtuelle Java crée java.lang.ref.Finalizer qui contient une référence à l’object créé, de sorte qu’elle ne soit pas récupérée avant la fin de la méthode finalize (). La fuite de mémoire provient de ces java.lang.ref.Finalizer-s qui ne sont pas effacés à temps. La suppression de ces finaliseurs est effectuée par un thread de démon de finaliseur distinct qui a une priorité inférieure. Par conséquent, si vous créez un grand nombre d’occurrences d’objects avec la méthode finalize () implémentée, vous manquerez de mémoire.

Tout est décrit très bien dans:

http://www.fasterj.com/articles/finalizer2.shtml

Voici ce qu’ils suggèrent comme solution:

“Un moyen évident consiste à augmenter la priorité du thread démon” Finalizer “- il n’y a pas d’API pour cela, vous devez donc parcourir tous les threads pour le trouver par son nom, puis augmenter sa priorité.”

Bonne chance