Почему GC не собирает мои объекты?

У меня есть программа Java, которая продолжает вызывать java.util.zip для сжатия / распаковки данных. Память заканчивается в течение нескольких секунд. У меня был дамп памяти с jmap и смотрю с jhat.

Сводка финализатора показывает Total instances pending finalization: 0. Если я правильно понимаю, у меня нет объектов, которые (1) имеют метод finalize (), (2) были отмечены GC и (3) ожидают завершения. Кажется, это хорошо.

Когда я смотрю на конкретный объект, единственная ссылка на этот объект - java.lang.ref.Finalizer. Объект Finalizer создается для каждого объекта, у которого есть метод finalize (), независимо от того, является ли объект сборщиком мусора или нет. Похоже, ничто не мешает этому Deflater объекту быть GC'ed.

Объект по адресу 0x7f4aeb7a35d0

экземпляр java.util.zip.Deflater@0x7f4aeb7a35d0 (51 байт)

Ссылки на этот объект:

java.lang.ref.Finalizer@0x7f4aeb8607c8 (64 байта): референт поля

Программа приостановлена ​​на System.in.read(). Использование памяти не снижается через некоторое время.

ОБНОВИТЬ:

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


person woodings    schedule 21.11.2012    source источник
comment
@dashrb Я не работаю с Deflater в своем коде. Я использую Apache Thrift, который использует Deflater. Deflater не входит в область действия, поскольку Show all members of the rootset показывает только 1 ссылку на класс Deflater, но не на экземпляры.   -  person woodings    schedule 21.11.2012
comment
Фактически, тот факт, что у вас заканчивается память и нет объектов, отмеченных GC, является плохим. Это означает, что ваш код (или какой-либо код библиотеки, который вы используете) хранит ссылки на объекты, поэтому GC не может их собрать.   -  person Ted Hopp    schedule 21.11.2012
comment
@TedHopp, вот что я собираюсь выяснить. Я не знаю, как найти эти ссылки, поскольку дамп памяти показывает, что ссылок не было.   -  person woodings    schedule 21.11.2012
comment
Если вы используете jmap для печати гистограммы распределения объектов, это может показать, какие объекты занимают память, и подскажет, где искать дальше. Есть хорошая статья здесь об инструментах для отслеживания утечек памяти. .   -  person Ted Hopp    schedule 21.11.2012
comment
Почему бы не использовать профиль памяти, чтобы увидеть, что именно живо и кто на кого ссылается?   -  person NPE    schedule 25.11.2012
comment
Вы можете попробовать что-то более удобное для пользователя, чтобы понять свой дамп памяти ... Eclipse MAT - это вариант: eclipse.org / мат   -  person Flavio    schedule 25.11.2012
comment
Ошибка OutOfMemory обычно содержит подсказку, есть ли проблема с кучей, PermGen, фрагментацией, сборщиком мусора и т. Д. Вы уверены, что ваша куча исчерпана?   -  person mazaneicha    schedule 26.11.2012
comment
Создайте цикл for, который будет вызывать System.gc () 5 раз. Доложить.   -  person Shark    schedule 29.11.2012
comment
Разархивируйте файл вручную и посмотрите, сколько данных внутри. Все найденные мной реализации Java Zip предполагают, что весь файл может быть прочитан в память и распакован там.   -  person Devon_C_Miller    schedule 30.11.2012


Ответы (5)


Вы уверены, что закрыли поток и вызвали end в дефлатере? Прошу прощения, если это упрощенное предложение, которое вы уже пробовали, но было много жалоб на утечку памяти при использовании Deflater, когда не вызывается сразу end, например:

Основная причина, по-видимому, в том, что сборщик не может успевать за приложением, когда задействована память, используемая собственными элементами. Это также объясняет поведение, которое вы наблюдаете при профилировании: память готова к высвобождению, но просто не восстанавливается достаточно быстро.

Поскольку вы написали, что используете Deflator не напрямую, а через Apache Thrift, попробуйте определить, какой метод в этой библиотеке отвечает за завершение дефлятора, и убедитесь, что вы вызвали этот метод.

person Oak    schedule 25.11.2012

Основная проблема заключается в том, что вы не освобождаете объекты из кучи C. Многие классы в java.util.zip используют Deflater. Deflater поддерживает ссылку на данные в куче C. Скорее всего, ваш код не вызывает close() на ZipOutputStream или DeflaterOutputStream или не вызывает end() на Deflater.

(Если вы передаете свой Deflater ZipOutputStream или DeflaterOutputStream, вы несете ответственность за вызов end() в Deflater.)

Сборка мусора в вашем случае может не очень помочь, потому что поток (потоки) необходимо разыменовать и, в конечном итоге, завершить. Это может занять несколько циклов GC. Я испытал аналогичную проблему с Jetty и предложил решение для нее.

person mikeslattery    schedule 26.11.2012

Добавление к ответу Мариана-Даниэля Крачунеску

У меня была такая проблема с другим типом использования.

Я нашел следующее решение:

  • Поместите объект на карту или в другое место, где вы можете легко оставить ссылку
  • Поместите также объект в WeakReference для его использования
  • Используйте свою ссылку как обычно
  • Удалите ссылку с карты там, где она больше не используется

Будьте осторожны с унаследованными ссылками

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

Вы никогда не узнаете, когда GC запущен, ни что он будет обрабатывать (кроме используемых объектов).

Полезная ссылка

Вам следует прочитать (если это еще не сделано) этот пост о WeakReferences: Общие сведения о ссылочных классах Java: SoftReference, WeakReference и PhantomReference

person Benj    schedule 30.11.2012

Прежде чем думать об утечке памяти, мы должны попытаться понять, является ли требование памяти нормальным для обработки, которую вы выполняете. Каков размер памяти, доступной JVM, т.е. -XmX. Если вы увеличиваете размер памяти или уменьшаете размер обрабатываемого файла, все же работает?

person Ashwinee K Jha    schedule 01.12.2012

Возможно, вам стоит использовать WeakReference для вашего объекта. Таким образом, GC может finalize () ваш объект намного быстрее

http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/ref/WeakReference.html http://weblogs.java.net/blog/2006/05/04/understanding-weak-references

person Marian-Daniel Craciunescu    schedule 28.11.2012