Почему GC не собирает мои объекты?
У меня есть Java-программа, которая продолжает звонить java.util.zip
сжать / распаковать данные. Он исчерпывает память в течение нескольких секунд. У меня был дамп памяти с jmap
и я просматриваю это с jhat
,
Финализатор сводных шоу Total instances pending finalization: 0
, Если я правильно понимаю, у меня нет объектов, которые (1) имеют метод finalize(), (2) помечены GC и (3) ожидают завершения. Это кажется хорошим.
Когда я смотрю на конкретный объект, единственная ссылка на этот объект java.lang.ref.Finalizer
, Объект Finalizer создается для каждого объекта, у которого есть метод finalize(), независимо от того, Ged-объект или нет. Так что, похоже, ничто не мешает этому Deflater
объект для GC'ed.
Объект в 0x7f4aeb7a35d0
экземпляр java.util.zip.Deflater@0x7f4aeb7a35d0 (51 байт)
Ссылки на этот объект:
java.lang.ref.Finalizer@0x7f4aeb8607c8 (64 байта): полевой референт
Программа приостановлена в ходе выполнения System.in.read()
, Использование памяти не снижается через некоторое время.
ОБНОВИТЬ:
Я должен сделать это ясно. Дамп памяти показывает, что многие объекты не были GC-объектами, но никакие другие объекты (кроме объектов Finalizer) не ссылались на них. Я пытаюсь выяснить, почему они не были GC'ed.
5 ответов
Вы уверены, что закрыли поток и вызвали end
на дефлят? Извините, если это упрощенное предложение, которое вы уже попробовали, но было много жалоб на утечку памяти при использовании Deflater
когда не сразу вызывая end
на это, например:
- http://www-01.ibm.com/support/docview.wss?uid=swg21227106
- http://bugs.sun.com/view_bug.do?bug_id=6734186 (1.5)
- чрезмерное использование памяти Java
- http://bugs.sun.com/view_bug.do?bug_id=4797189
- http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6293787
- http://kohsuke.org/2011/11/04/quiz-answer-memory-leak-in-java/
Основная причина, по-видимому, заключается в том, что сборщик не может не отставать от приложения, когда задействована память, используемая нативными элементами. Это также объясняет поведение, которое вы видите при профилировании: память готова к восстановлению, но не восстанавливается достаточно быстро.
Поскольку вы написали, вы не используете Deflator
напрямую, но через Apache Thrift, попытайтесь определить, какой метод в этой библиотеке отвечает за завершение дефлятора, и убедитесь, что вы вызвали этот метод.
Основная проблема в том, что вы не освобождаете объекты из кучи C. Многие классы в java.util.zip используют Deflater
, Deflater поддерживает ссылку на данные в куче Си. Ваш код, вероятно, не звонитclose()
на ZipOutputStream
или же DeflaterOutputStream
или это не звонит end()
на Deflater
,
(Если вы передаете свой собственный Deflater
в ZipOutputStream
или же DeflaterOutputStream
, вы несете ответственность за звонки end()
на Дефлатере.)
GC имеет ограниченную помощь в вашем случае, потому что поток (ы) должен быть разыменован и в конечном итоге завершен. Это может занять несколько циклов ГХ. Я столкнулся с подобной проблемой с Jetty и предложил исправить ее.
Добавление к ответу Мариана-Даниэля Крачиунеску
У меня была такая проблема с другим типом использования.
Решение, которое я нашел, заключается в следующем:
- Поместите объект на карту или куда-нибудь, где вы можете легко опустить его ссылку
- Поместите также объект в WeakReference для его использования
- Используйте вашу ссылку как обычно
- Удалить ссылку с карты, где больше не используется
Будьте осторожны с унаследованными ссылками
Вполне возможно, что ваш объект "скрыт-на-внутренняя ссылка" в другом объекте, используйте отладчик и "разверните" все объекты, используя его.
Вы никогда не узнаете, когда GC работает, и что он будет обрабатывать (кроме используемых объектов).
Полезная ссылка
Вы должны прочитать (если это еще не сделано) этот пост о WeakReferences: понимание справочных классов Java: SoftReference, WeakReference и PhantomReference
Прежде всего, прежде чем думать об утечке памяти, мы должны попытаться понять, является ли требование к памяти нормальным для обработки, которую вы выполняете. Какой размер памяти доступен для JVM, т. Е. -XmX. Если вы увеличиваете размер памяти или уменьшаете размер обрабатываемого файла, это работает?
Возможно, вам следует использовать WeakReference для вашего объекта. Таким образом, GC может очень быстро завершить () ваш объект
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 -Рекомендации