ICE09 . playing with java, scala, groovy and spring .

Playing with Spring

Archive for July, 2009

Analysing Memory Leaks with BTrace

Posted by ice09 on July 12, 2009

After having experimented with Eclipse Galileo and the now included Memory Analyzer in the last post, I came across BTrace, which very nicely fits to the tool chain for analyzing Memory Leaks and/or performance problems in applications.

Continuing the problem analysis from the last post, after having found out the resulting object for the memory leak (leakingSet), it would be interesting to find out where the objects are inserted.

Preparation

  1. Download visualvm
  2. Install the BTrace plugin as described here
  3. Extend the object insertion with a Thead.sleep (I used 100ms)
  4. Start the sample application

Usage

  1. Start visualvm and search for the started application PID
  2. Start tracing…
  3. Install the following script
import com.sun.btrace.annotations.*;
import com.sun.btrace.AnyType;
import static com.sun.btrace.BTraceUtils.*;

@BTrace public class TraceLeakingSet {
    @OnMethod(
        clazz="+java.util.Set",
        method="add"
    )
    public static void method(AnyType[] arg) {
        print(strcat("entered ", name(probeClass())));
        print(strcat(".", probeMethod()));
        println(strcat(" with argument ", str(arg[1])));
        jstack();
        println();
    }
} 

The script will log every call to the method “add” on all subclasses of “java.util.Set” (that’s the “+”). The submitted argument is included in the first index of the AnyType array.
probeClass and probeMethod display the called class and method, jstack() displays the real stack trace. This is most useful, together with the display of class, method and argument.

Sample output is as follows:

BTrace code successfuly deployed
===========================================================
entered java.util.HashSet.add with argument scopedTarget.scopetest
java.util.Collections$SynchronizedCollection.add(Collections.java:1577)
org.springframework.beans.factory.support.AbstractBeanFactory.markBeanAsCreated(AbstractBeanFactory.java:1257)
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:256)
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:175)
org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:33)
org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.getTarget(Cglib2AopProxy.java:657)
org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:608)
com.commons.Scopetest$$EnhancerByCGLIB$$3824588a.uniqueCode()
com.commons.Tester.start(Tester.java:25)
com.commons.Tester.main(Tester.java:14)

entered java.util.HashSet.add with argument -841086979
com.commons.Tester.start(Tester.java:25)
com.commons.Tester.main(Tester.java:14)

So there are two alternating locations where add is called on Set and it’s subclasses, one location is in Spring itself (which is interesting but of no concern for the problem) and – of course – the line where the object is added in the start method. This is the location we are looking for – the question would be why so many objects are added with different arguments (instead of always the same argument with singleton instead of prototype usage).

So, BTrace is very easy to use and very useful for tracking problems in running systems with very low overhead and low intrusion (there is actually no change at the deployed code necessary).

Advertisements

Posted in BTrace, Performance testing | 9 Comments »