Wednesday, May 27, 2009

Anonymous Logger Memory Leak

I was helping a development group uncover the cause of a memory leak a while back, and figured I should share the finding here.

The memory leak in this case was induced by the static method "getAnonymousLogger()" on the class "java.util.logging.Logger"; although it looks like it could be caused by any logger that sets a parent in code. When an anonymous logger is created, it is created from scratch, and the root looger is set as the parent.

When a logger has its parent set in code, a weak reference is created on the parent for its list of "kids". This design allows short lived loggers to be garbage collected even though the parent maintains a reference to the logger. Great in theory, but missing a component in the current implementation. The current implementation never cleans up the weak reference objects. That is, the memory used by the Logger is freed, but the weak reference held by the parent is not. Those interested in the bug can get the JDK source code, and look at the private doSetParent(Logger) method on the Logger class.

Calling setParent or getting an anonymous logger leaks a minuscule amount of memory per invocation. In applications that run for a very short period of time (like an applet), this is probably unnoticeable. When called per invocation of a servlet in a long running j2ee container, it will eventually kill your JVM instance.

So how do you get around it? My first suggestion is to never use getAnonymousLogger unless you have an exceptionally good reason (probably involving the security manager). My second suggestion is to save a reference to the Logger object as a member field, and always reuse that reference.