Wednesday, 2 May 2012

Talk at JUGS

Today I gave a talk at Java User Group Scotland. The talk covered the material in my last three posts along with the Java Live Thread Analyser. I demoed InTrace, InMemProfiler and JLTA and talked about how they worked.

The slides from my talk are available here.

InMemProfiler

The next instrumentation tool which I wrote (also started in 2010) was motivated by a session using the excellent VisualVM memory profiling to investigate why an application was performing profligate memory allocation. The results in VisualVM are presented as a tree of allocation stack traces.

This was frustrating in some cases. For example a string constructed from several parts results in stack traces through StringBuilder.append() as well as through StringBuilder.toString(). In practice I would prefer to see both of these allocations presented together as the methods are called from the same site. I also wanted to get a summary of the lifetime of the objects being allocated grouped together into buckets. This is something which VisualVM doesn't offer at all - the closest thing available is an indication of the number of GCs which an object has survived.

I managed both of these by using the JVM TI API to write an agent that added an InMemProfiler method call into the java.lang.Object constructor and after every array allocation (as these don't use the Object constructor). This instrumentation is done with the native JVM TI API.

When profiling object lifetimes the profiler code creates a Java weak reference for each allocated object to detect when it has been collected. The tracking of collection could be done much more efficiently using the native JVM TI object tagging mechanism but I wanted to do as much as possible using Java.

For further information you should refer to my GitHub page: http://mchr3k.github.com/org.inmemprofiler/

InTrace

In my last post I introduced the low level APIs available in the JVM.

The first tool which I wrote to use the java.lang.instrument API was InTrace which I started in the summer of 2010. This tool was written to allow the execution of any Java program to be traced - method entry, exit, method args, thrown exceptions, caught exceptions and execution path within methods. All of this is made possible by inserting InTrace method calls into classes. This can be done at any time thanks to the JVM's support for redefining already loaded classes.

There are two parts to InTrace. The InTrace Agent allows for the dynamic instrumentation of Java classes to add trace calls. The InTrace UI allows for the remote control of the InTrace Agent and collection of trace output.

To get started with InTrace you can use the Agent and UI directly. However, I have also written an Eclipse plugin which automates the process of launching a program with the agent and connecting to the launched program with the UI.

Java Instrumentation APIs

Historically there were two low level APIs within the JVM:
Both of these were deprecated in Java 5 and removed in Java 6. The replacement introduced in Java 6 was the JVM Tools Interface. This is a native C API but there is an equivalent available in two parts in pure Java. The Java Debug Interface and the java.lang.instrument package. One of the most noticeable changes made in the switch from JVMPI to JVMTI was the reliance on bytecode instrumentation for tracking method entry/exit and object allocation. The justification for this was to allow the profiling code to be optimised along with the code being profiled to minimise the overall performance impact.

In my opinion the most interesting part of all of this is that the current JDI and java.lang.instrument APIs allow for interesting debugging and profiling tools to be written in pure Java. In other words, if you are an experienced Java developer, it is relatively easy for you to write great tools that interact with the internals of the JVM and the running of Java program's.