DTrace Probes in Java SE
If you are familiar with DTrace, then peering into the JVM is a simple matter of learning a few new probes. If not, then you should definitely take the time to read the Solaris Dynamic Tracing Guide
who can code in Java will have no trouble picking up the D language in almost no time.
The first thing you should understand is how to enable the DTrace probes in Java SE 6. By default, a small subset of the probes that have no measurable performance impact are enabled. These probes allow you to see events like garbage collection, method compilation, thread creation, and class loading.
The probes with measurable performance impact are disabled by default. These are probes for object allocation, method invocation, and Java monitor events. You can enable them on the command line or dynamically through by using the Java jinfo command. The following are the command line options:
The first three are self-explanatory, and the last option enables all DTrace probes in the JVM. As for their performance impacts, precisely quantifying what the probe-effect will be is impossible. However, it is safe to say that it will be less than a JVMTI-based approach and somewhat proportional to the frequency at which the probes fire. So for instance, method invocationa very frequent eventwill carry a higher probe-effect than monitor probes in most cases. Therefore, it is wise to enable only those probes that you need if possible.
A Simple Java/DTrace Example
It has become a bit of a standard to use one of the Java demo applications to showcase the Java/DTrace combo. This article uses the $JDK_HOME/demo/jfc/Java2D demo as an example since it is readily available (and you get to watch surfing Duke!). If you wanted to look at object allocation in this application, you could start your process with the appropriate double X option as follows:
java -XX:+DTraceAllocProbes -jar Java2Demo.jar
Currently, only ExtendedDTraceProbes can be enabled dynamically using jinfo. If you wanted to enable all of the DTrace probes in your application after it has started, you could do that with jinfo:
jinfo -flag +ExtendedDTraceProbes <pid of JVM>
Now that you have your probes enabled, you can dive in and see what information is available. First, you need to know that the provider name for the JVM probes is hotspot (see Listing 1). Using this provider, you have access to the probes within the JVM (there is also the hotspot_jni provider for observing JNI events, but that will be left for another article).
To use the hotspot provider, you append the processes ID of the JVM of interest to the provider name "hotspot". So, if your process ID was 116977, your provider would be "hotspot116977". Using that, you can begin to profile your application.
If the first thing you wanted to look at was object allocation (maybe you are seeing frequent garbage collections), you would use the object-allocation probe (see Listing 2).
With this data in hand, you might be curious as to where in your application you are allocating those Integer arrays. You could follow up with another simple DTrace script that will show you your stack at the point of allocation (see Listing 3).
One of the things you might note is that there are several native code frames on this stack. That is an artifact of the implementation and it is necessary for the DTrace interaction. If you have used one of the hotspot probes (as opposed to a native probe point), you can generally ignore these native code frames.
With just a couple of simple DTrace scripts, you have identified the objects you are allocating (as well as total size over the interval) and determined where in your code you induce an allocation of one of those objects.