5

By "released" I mean there are no references to the classloader remaining.

We're running into a problem where a frequently-redeployed Java EE application eats up permgen space. Analysis shows that a singleton in the Java EE app has passed references to application-classloader objects outside of the application (in violation of Java EE rules) and isn't clearing them when the app is undeployed.

Assuming there are no other references remaining to the singleton or the class object, will the singleton's finalize() be called when its class's classloader is released? I'd like to clear the rogue in-bound references there. Or am I in a catch-22 where finalize won't get called until the classloader itself can be garbage-collected - and thus will never be called because of the rogue external references?

The main question here is perhaps:

Will a class object be garbage-collected in this case where its classloader can't be yet? This may be dependent on the specification of classloader behavior, or may be implementation-dependent.

References (the other kind! ;-)) would be appreciated, but aren't necessary.

Arjan Tijms
  • 37,782
  • 12
  • 108
  • 140
Ed Staub
  • 15,480
  • 3
  • 61
  • 91
  • If you pass references of ClassLoaders consider using WeakReference(s) and WeakHashMap instead of strong(regular) references. – Stefan Feb 28 '12 at 22:27

2 Answers2

4

A class with a static reference to it, will is eligible for garbage collection only, if the class loader is eligible for GCing and there are no other references to it.

A class or interface may be unloaded if and only if its defining class loader may be reclaimed by the garbage collector.

http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.7

Furthermore every class has a reference to its classloader. So a class loader is not eligible for GCing as long as there are references to classes loaded by it or objects of those classes from a non collectible objects.

The finalizer is run some time after an object becomes eligible for garbage collection and before the actual GC takes place.

The approach to free incoming references, that prevent GCing, in a finalizer does not work. The finalizer will not be called as long as such references exist because they prevent the object from becoming eligible for garbage collection. For example you cannot break this reference chain from the inside:

singleton instance <--- singleton class <--- class loader <--
<-- any class loaded by that class loader  <-- any object of such a class
<-- object loaded by another classloader referencing such an object or class
Hendrik Brummermann
  • 8,242
  • 3
  • 31
  • 55
  • The references are not to the singleton (directly or indirectly), so that reference loop is not an issue. The main thing I'm trying to understand is if the class can be GC'd even though there are external references outstanding to other classes from this released classloader. – Ed Staub Feb 28 '12 at 21:39
  • What do you mean by "released". A class loader only becomes eligible for GCing, if all classes loaded by it are also eligible for GCing as every class has a reference to its classloader. – Hendrik Brummermann Feb 28 '12 at 21:45
  • Ok, and ClassLoader has a vector of all the classes it has loaded... so finalizer won't work regardless. Thanks much! – Ed Staub Feb 28 '12 at 21:58
1

The behaviour of finalisers is not changed the class loader or the use of perm gen, although it does make the performance issue worse. Objects cannot be collected until after the finaliser is run. So (simplifying by assuming non-concurrent, and ignoring weak/soft/phantom) there is a run of the GC that determines that there are no active references to the object graph including the class loader. The finalisers are added to the finaliser queue and then executed. Then after some subsequent pass of the GC the memory can be recovered. This requires a full GC including over the perm gen space, which is generally infrequent and can be disabled.

Anyway, don't use (stateful) singletons.

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
  • Will a class object be garbage-collected in this case where its classloader can't be yet? This is either dependent on the specification of classloader behavior, or may be implementation-dependent. – Ed Staub Feb 28 '12 at 21:35
  • @EdStaub -- A class is NEVER collected until its classloader can be collected. And a classloader is never collected until ALL classes it loaded can be collected. – Hot Licks Feb 28 '12 at 21:52
  • And static references are still reachable whilst the class is reachable. "Interestingly," Tomcat will null out static fields. – Tom Hawtin - tackline Feb 28 '12 at 21:58