trying to discover which methods instantiate an object

  2 posts   Feedicon  
Replies: 1 - Last Post: December 10, 2011 23:10
by: Jaroslav Bachorik
showing 1 - 2 of 2
 
Posted: December 05, 2011 06:21 by daghanacay
Hi there,

I am tracing the memory usage in my application using visualVM and Btrace plug in. I can see that a particular class, namely gov.nasa.worldwind.geom.Position is using extra large memory. Since it is a 3rd party class it is created in many places including my code.

I would like to identify which method instentiates the largest amount of the class so that I can refactor that method instead of refactoring every method where the class is used.

I have used couple of BTrace scripts modifying the example scripts to the best of my understanding:
  
import static com.sun.btrace.BTraceUtils.*;
import com.sun.btrace.annotations.*;
import gov.nasa.worldwind.geom.Angle;

/**
 * A simple BTrace program that prints stack trace
 * whenever a class is loaded by a user-defined
 * class loader. We insert a return point probe in
 * ClassLoader.defineClass method to detect successful
 * class load.
 */
@BTrace public class Classload {
   @OnMethod(
     clazz="gov.nasa.worldwind.geom.Angle", 
     method="<init>",
     location=@Location(Kind.RETURN)
   )   
   public static void defineclass(@Return Class cl) {
       println(Strings.strcat("loaded ", Reflective.name(cl)));
       println("==========================");
   }
}

the code above throws null pointer exception. The reason, I believe, is that "<init>" method cannot be found. I have changed the "<init>" to "/*/" and received invalid regex pattern exception. also changed "<init>" to "add" which is a public API of the class. This time the script compiles but cannot be started.

Any help will be appreciated. If this cannot be done by BTrace can you direct me to a profiler which can do what I want?

regards
-Daghan
 
Posted: December 10, 2011 23:10 by Jaroslav Bachorik
Hi Daghan,

there are few problems with your script:
  • Constructor provides no return value by definition. And even if it would it wouldn't be a "Class" but rather a new instance
  • You are not capturing the information about the place a constructor is invoked from


You would rather need a script like this:
import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;

import java.util.Deque;
import java.lang.String;

@BTrace
public class TracingScript {
    @TLS
    // keep the per-thread stack of my custom code calls
    private static Deque<String> eStack = newDeque();
    
    @TLS
    // keep the per-thread latest call to my custom code (equals to the top of the stack)
    private static String current;
    
    @OnMethod(clazz="/java2d\\..*/", method="/.*/")
    // mark down the entry to the custom code
    public static void noteCustomEntry(@ProbeMethodName(fqn=true) String m) {
        push(eStack, m);
        current = m;
    }
    
    @OnMethod(clazz="/java2d\\..*/", method="/.*/", location=@Location(Kind.RETURN))
    // move up the stack
    public static void noteCustomExit() {
        current = poll(eStack);
    }
    
    @OnMethod(clazz="java.awt.Dimension", method="<init>")
    // this is the place where you capture the constructor invocation; you have the caller on the stack
    public static void site() {
        if (current == null) return;
        println(strcat("a new Dimension created @", current));
    }
}


This piece of code should do exactly what you want.
Edited
Also, you should be able to achieve the same result by using Kind.CALL in @Location - unfortunately it seems to have some issues specifically in conjunction with constructors.

Actually, you need to use Kind.NEW for tracking instance creation. Using this kind of location the script would look like this:

import com.sun.btrace.annotations.*;
import static com.sun.btrace.BTraceUtils.*;
import com.sun.btrace.AnyType;

import java.util.Deque;
import java.lang.String;

@BTrace
public class InstanceTracker1 {
	@OnMethod(
        clazz="/java2d\\..*/", 
        method="/.*/", 
        location=@Location(
            value=Kind.NEW,
            clazz="java.awt.Dimension"
        )
    )    
    public static void site(@ProbeMethodName(fqn=true) String caller) {
         println(strcat("a new Dimension created @", caller));
    }
}



Regards,

-JB-
Replies: 1 - Last Post: December 10, 2011 23:10
by: Jaroslav Bachorik
  • Mysql
  • Glassfish
  • Jruby
  • Rails
  • Nblogo
Terms of Use; Privacy Policy;
© 2010, Oracle Corporation and/or its affiliates
(revision 20120518.3c65429)
 
 
Close
loading
Please Confirm
Close