During component testing at our project we have
discovered a memory leak.
We use EasyMock and EasyMock extension for mocking
and some profiling (using TPTP Eclipse) has lead us
to CGLIB used by EasyMock extension.
Next I have taken the Trace example to see if the
leak occurs when CGLIB is used in a isolated way.
And it did occur.
I have split up the Trace example, taken from the
cglib project site, into 3 classes; Trace,
TraceCallback and TraceTest.
(See attachments)
Trace contains most of the original code (the main
method is replaced by a run method).
TraceCallback contains the MethodInterceptor
implementation.
TraceTest is just a main class, instantiating the
Trace class and calling the run method. The callback
varuiabele is no longer static (for garbage
collecting).
After running the Trace example (trace.run()), the
Trace object is set to null and a garbage collected
is requested (and executed, -verbose:gc VM argument
is used for logging).
Last line of the console output:
be.Trace@1feca64is done.
[Full GC[Unloading class
sun.reflect.GeneratedConstructorAccessor1]
1185K->305K(1984K), 2.7442951 secs]
Taking lock for profiling
Next an infinite Object.wait() is done to profile the
current situation.
As you can see in the screenshot (profiling.jpg), the
Trace object has been collected but the TraceCallback
is still referenced.
Also 92 AbstractList$$FastClassByCGLIB$$
Vector$$EnhanceByCGLIB$$xxx and
Vector$$FastClassByCGLIB$$ objects are still in
memory, none of them are collected.
If the Trace.run is executed twice on 2 different
objects, 93 Objects of the java.util package. An
additional Vector$$EnhancerByCGLIB$$ is created.
When running all unit tests at once (over 1000 unit
tests), OutOfMemory errors occur.
I also tried it with the latest beta (cglib-nodep-
2.2_beta1.jar) but the behaviour is the same.
The JDK I have used is JDK 1.5.0_06.
Regards,
Gert Claes
Source files and sreenshot