2

I run client code inside my application, much like a WebServer deploys/undeploys WebApps.

So I created a custom ClassLoader that gets discarded to get rid of the client code. However, this doesn't work properly. When executing and analyzing with Elipse Memory Analyzer, I can see that the objects and the classloader are never garbage collected: Path to Memory Leak

Somehow the problem seems to be related to the ThreadPoolExecutor, which implements a finalize() method. It was mentioned elsewhere, that finalizer methods are evil and can cause OutOfMemoryErrors, because Finalizer thread runs with lower priority. However, when analyzing the application and thread stack with VisualVM, the Finalizer thread is not busy but waiting for new work to arrive:

"Finalizer" daemon prio=5 tid=0x00007fdb1484f800 nid=0x2603 in Object.wait() [0x000000010aaf6000]
java.lang.Thread.State: WAITING (on object monitor)
 at java.lang.Object.wait(Native Method)
 - waiting on <0x000000079aaadf10> (a java.lang.ref.ReferenceQueue$Lock)
 at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
 - locked <0x000000079aaadf10> (a java.lang.ref.ReferenceQueue$Lock)
 at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
 at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:177)

Locked ownable synchronizers:
 - None

JavaDoc of ReferenceQueue.remove(ReferenceQueue.java:135):

Removes the next reference object in this queue, blocking until either 
one becomes available or the given timeout period expires.

Any ideas what can cause this problem and what to do about it? Every input is highly appreciated!

Edit: We are using jdk1.7.0_09.jdk, so I guess it has nothing to do with this bug.

Edit: When I let the application run long enough (and execute and discard enough client code) I do get OutOfMemoryErrors, so the VM should garbage collect the classes. Also, using the -verbose:gc flag, I see the following log output after the classes should be ready for finalization and just before taking the HeapDump:

[Full GC 57007K->52790K(149544K), 0.2997010 secs]

Which means, that a full GC just took place.

Community
  • 1
  • 1
roesslerj
  • 2,611
  • 5
  • 30
  • 44
  • 1
    Are you actually getting OOME's? Because without those there is no pressure on the JVM to collect. And of course, dumping the whole application without proper shutdown is a sure road to failure. – Marko Topolnik Sep 18 '14 at 13:37
  • @MarkoTopolnik: Thanks for pointing that out, adjusted the question accordingly... but what do you mean with 'dumping the whole application without proper shutdown'? – roesslerj Sep 18 '14 at 13:45
  • Just losing the ClassLoader is not enough to properly dispose of an application. A reasonable architecture will provide a callback to the application where it would run the cleanup procedure, shutting down the executor service, for example. – Marko Topolnik Sep 18 '14 at 13:55
  • The `ThreadPoolExecutor.shutdown()` method gets called. I just provided a ThreadPoolExecutor without `finalize()` (via -Xbootclasspath/p:) and now there are some other objects which are referenced from a Finalizer. Since no additional thread is still running ... how can that be? – roesslerj Sep 19 '14 at 09:08

1 Answers1

1

After trying everything else, I updated the JDK and ... now the problem is gone. Now we are using jdk1.7.0_51 instead of jdk1.7.0_09.

Hope this helps someone...

roesslerj
  • 2,611
  • 5
  • 30
  • 44