Устранение утечки памяти Java: завершение? - PullRequest
12 голосов
/ 04 октября 2011

У меня неправильное приложение, которое, кажется, течет.После краткого исследования профилировщика большая часть памяти (80%) удерживается java.lang.ref.Finalizer экземплярами.Я подозреваю, что финализаторы не работают.

Распространенной причиной этого, по-видимому, являются исключения из финализатора.Тем не менее, Javadoc для метода finalize класса Object (см., Например, здесь ), кажется, противоречит сам себе: он заявляет

Если выброшено необработанное исключениес помощью метода finalize исключение игнорируется, и завершение этого объекта завершается.

, но позже также указывается, что

Любое исключение, выброшенное методом finalize, вызываетзавершение этого объекта должно быть остановлено, но в противном случае игнорируется.

Во что мне следует верить (т. Е. Остановлена ​​ли финализация или нет?), И есть ли у вас какие-либо советы о том, как исследовать такие явные утечки?

Спасибо

Ответы [ 5 ]

9 голосов
/ 04 октября 2011

Обе кавычки говорят:

Исключение приведет к остановке / прекращению завершения этого объекта.

Обе кавычки также говорят:

Неисследованное исключение игнорируется (то есть не регистрируется и не обрабатывается виртуальной машиной каким-либо образом)

Так что это ответит на первую половину вашего вопроса.Я не знаю достаточно о Finalizer, чтобы дать вам совет по отслеживанию утечки памяти.

РЕДАКТИРОВАТЬ: Я нашел эту страницу , которые могут быть полезны.У него есть совет, такой как установка полей в null вручную в финализаторах, чтобы GC мог их вернуть.

EDIT2: Еще несколько интересных ссылок и цитат:

От Анатомия финализатора Java

Потоки финализатора не имеют максимальных приоритетов в системах.Если поток «Финализатор» не может идти в ногу со скоростью, с которой потоки с более высоким приоритетом приводят к очереди финализируемых объектов, очередь финализатора будет продолжать расти и вызывать заполнение кучи Java.В конце концов, куча Java будет исчерпана, и будет выдано java.lang.OutOfMemoryError.

, а также

не гарантируется, что любые объекты, имеющие finalize ()метод - сборщик мусора.

EDIT3: После прочтения дополнительной ссылки Anatomy выясняется, что создание исключений в потоке Finalizer действительно замедляет его, почти так же, как вызов Thread.yield ().Похоже, вы правы, что поток Финализатора в конечном итоге пометит объект как способный к GC, даже если выдается исключение.Однако, поскольку замедление является значительным, возможно, что в вашем случае поток Finalizer не поспевает за скоростью создания и выпадения объектов из области видимости.

6 голосов
/ 04 октября 2011

Моим первым шагом было бы установить, является ли это подлинной утечкой памяти или нет.

Все вопросы, поднятые в предыдущих ответах, относятся к скорости , на которой собираются объекты, а не к вопросу о том, собраны ли ваши объекты вообще. Только последняя является настоящей утечкой памяти.

У нас было похожее затруднение в моем проекте, и мы запустили приложение в режиме «замедленного движения», чтобы выяснить, была ли у нас настоящая утечка. Мы смогли сделать это, замедлив поток входных данных.

Если проблема исчезает при запуске в режиме «замедленного движения», то проблема, вероятно, одна из тех, которые были предложены в предыдущих ответах, т. Е. Поток Finalizer не может обработать очередь финализатора достаточно быстро.

Если это проблема, может показаться, что вам может потребоваться выполнить нетривиальный рефакторинг, как описано на странице Bringer128, связанной, например, с.

Теперь давайте посмотрим, как писать классы, которые требуют посмертной очистки, чтобы их пользователи не сталкивались с ранее описанными проблемами. Лучший способ сделать это - разделить такие классы на два - один для хранения данных, которые требуют посмертной очистки, другой для хранения всего остального - и определения финализатора только для первого

2 голосов
/ 04 октября 2011

Пункт 7 вступает в силу Второе издание Java : " Избегайте финализаторов ". Я настоятельно рекомендую вам прочитать это. Вот выдержка, которая может вам помочь:

«Явные методы завершения обычно используются в сочетании с конструкцией try-finally для обеспечения завершения»

0 голосов
/ 25 декабря 2013

Я однажды видел подобную проблему, то есть поток финализатора не может догнать скорость генерации финализируемых объектов.

Мое решение - создать элемент управления с замкнутым циклом, используя MemoryMXBean .getObjectPendingFinalizationCount (), элемент управления PD (proportinal и diffrential) для управления скоростью, с которой мы генерируем финализуемые объекты, поскольку у нас есть одна запись для его создания , просто сон количество секунд с результатом pd algo. это работает хорошо, хотя вам нужно настроить параметр для pd algo.

надеюсь, это поможет.

0 голосов
/ 22 февраля 2013

У меня такая же проблема с вами (на картинке ниже).В нашем случае это потому, что объект имеет wait(0) в своей финализации, и он никогда не получает уведомление, что блокирует java.lang.ref.Finalizer $ FinalizerThread.Дополнительная информация

objects retained by Finalizer

...