Подтвердить что ты не робот

Утечка утечки памяти, VisualVM: "Не найдено GC root". Что дальше?

У меня есть дамп памяти, который я сделал из умирающего приложения. Он потребляет всю доступную кучу (-Xmx1024m). Он использует com.gargoylesoftware.htmlunit.WebClient для обхода веб-страниц. Делает несколько HTTP-запросов в минуту, умирает через несколько дней. Как видно из дампа, он имеет ~ 1750 экземпляров класса HtmlPage, каждый из которых имеет тоны связанных объектов, включая полное содержимое обходной страницы.

Я не могу понять, почему HtmlPage не собирают мусор. Я изучил ссылки на экземпляры, и я не вижу, чтобы какой-либо мой код содержал ссылку на него, а VisualVM говорит, что "никакой корень GC не найден". Насколько я понимаю, это означает, что объект имеет право на gc, но он не работает.

Приложение работает как простой автономный процесс, он не использует веб-контейнеры или серверы приложений.

Любые подсказки? Что еще я должен изучить?

Технические характеристики:

  • htmlunit v2.7
  • версия java "1.6.0_13" Java (TM) SE Runtime Environment (сборка 1.6.0_13-b03) Java HotSpot (TM) Server VM (сборка 11.3-b02, смешанный режим)
  • Linux my.lan 2.6.18-128.el5 # 1 SMP Wed Dec 17 11:42:39 EST 2008 i686 i686 i386 GNU/Linux

Update1

Я попытался проанализировать дамп с помощью MyKit Java Profiler. Это показывает мне много объектов java.lang.ref.Finalizer с сохраненным размером 310mb. Они созданы для финализатора net.sourceforge.htmlunit.corejs.javascript.NativeGenerator#finalize(), а NativeGenerator - Window, затем HtmlPage и ко всему.

Кто-нибудь знает, почему они остаются в памяти?

Примечание: Любопытно, но VisualVM показал "ожидающий завершения" как ноль.

4b9b3361

Ответ 1

Удостоверьтесь, что вы вызываете webClient.closeAllWindows() после того, как вы закончили работу со страницами. В противном случае поток JavaScript продолжает запускать ссылки на ресурсы страницы и т.д.

Ответ 2

Когда объект имеет нетривиальный метод finalize(), при создании экземпляра объекта JVM создает java.lang.ref.Finalizer, который содержит ссылку на созданный объект, поэтому он не получает мусор, собранный до метода finalize() закончен. Утечка памяти исходит из тех java.lang.ref.Finalizer, которые не очищаются вовремя. Очистка этих финализаторов выполняется отдельным потоком демона финализатора, который имеет более низкий приоритет, поэтому, если вы создаете множество экземпляров объектов с реализованным методом finalize(), то время, когда у вас заканчивается память.

Все это очень хорошо описано в:

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

Это то, что они предлагают в качестве решения:

"Один из очевидных способов - увеличить приоритет потока" Finalizer "daemon - для этого нет API, поэтому вам нужно пропустить все потоки, чтобы найти его по имени, а затем увеличить его приоритет".

Удачи.