Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why GC doesn't collect my objects?

I have a java program which keeps calling java.util.zip to compress/decompress data. It runs out of memory within a few seconds. I had a memory dump with jmap and I'm viewing it with jhat.

Finalizer summary shows Total instances pending finalization: 0. If I understand it correctly, I don't have any objects which (1) have finalize() method, (2) have been marked by GC and (3) are waiting to be finalized. This seems good.

When I look at a particular object, the only reference to this object is a java.lang.ref.Finalizer. The Finalizer object is created for each object which has a finalize() method no matter if the object is GC'ed or not. So it looks like nothing is preventing this this Deflater object to be GC'ed.

Object at 0x7f4aeb7a35d0

instance of java.util.zip.Deflater@0x7f4aeb7a35d0 (51 bytes)

References to this object:

java.lang.ref.Finalizer@0x7f4aeb8607c8 (64 bytes) : field referent

The program is paused in the run by System.in.read(). The memory usage doesn't go down after a while.

UPDATE:

I should make it clear. The memory dump shows many objects were not GC'ed but no other objects (except Finalizer objects) were referencing them. I'm trying to find out why they were not GC'ed.

like image 236
woodings Avatar asked Nov 21 '12 18:11

woodings


People also ask

Which object is eligible for GC?

An object is eligible to be garbage collected if its reference variable is lost from the program during execution. Sometimes they are also called unreachable objects. What is reference of an object? The new operator dynamically allocates memory for an object and returns a reference to it.

Is GC collect blocking?

It also freezes the main thread (and also any child threads it created) of the application. In other words, when the GC. Collect() method is called, the runtime performs a blocking garbage collection of all generations.

How does GC collect work?

It performs a blocking garbage collection of all generations. All objects, regardless of how long they have been in memory, are considered for collection; however, objects that are referenced in managed code are not collected. Use this method to force the system to try to reclaim the maximum amount of available memory.


1 Answers

Are you positive you closed the stream and invoked end on the deflater? I'm sorry if this is a simplistic suggestion you've already tried, but there were a lot of complaints about a memory leak when using Deflater when not immediately invoking end on it, for example:

  • http://www-01.ibm.com/support/docview.wss?uid=swg21227106
  • http://bugs.sun.com/view_bug.do?bug_id=6734186 (1.5)
  • excessive memory use by 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/

The root cause is apparently that the collector is not able to keep up with the application when memory used by native elements is involved. That also explains the behavior you are seeing when profiling: the memory is ready to be reclaimed, but just isn't reclaimed quickly enough.

Since you wrote you don't use a Deflator directly but through Apache Thrift, try to identify which method in that library is responsible for ending the deflator, and made sure you invoked that method.

like image 182
Oak Avatar answered Oct 01 '22 19:10

Oak