I studied physics at university and one of the hardest, but most interesting, subjects was quantum mechanics. As part of this, we studied the famous Heisenberg’s Uncertainty Principal, which is also associated with the “Observer Effect”. Essentially, what this says is that the act of observing something (at the sub-atomic level) changes what you’re observing so that you can either know a particle’s position or momentum with accuracy, but not both at the same time. Right now I’m sure you’re wondering what this has to do with Java but bear with me.
Analysing performance in Java is not always straightforward because of the non-deterministic nature of the JVM. Memory management and specifically garbage collection is frequently cited as the cause for unresponsiveness in an application, and indeed, this is often the case. With the exception of C4 in Zing from Azul, all commercial garbage collectors (GCs) will use a full compacting stop-the-world collection of the old generation as a fallback to avoid throwing the undesirable OutOfMemoryError. The length of pause of application threads and, therefore, the application itself is proportional to the size of the heap: the bigger the heap, the longer the pause.
To analyse Java application performance requires special tools of which there are many to choose from, but this is where Heisenberg’s Uncertainty Principal becomes relevant to Java. To measure things (like GC pause times) involves the collection of data, which requires time and computing resources. Using processor cycles and writing to memory will reduce the resources available to application code, even if very slightly. The more fine-grained analysis you want to do, the more data needs to be collected and the bigger the impact you will have on the application’s performance. I’ve actually worked on some timing related bugs where adding debug code to collect data about the problem skewed things enough to make the problem disappear (which leaves you with a tricky decision: leave the debug code in and ignore the problem, or find some other way to fix it).
In the case of the garbage collector, most of the performance data is effectively available for free simply because the collector has to keep track of information as it does its own work. Unfortunately, it’s not true to state that because GC can cause significant pauses in Java applications, all significant pauses must be due to GC. There are other things within the JVM, like thread management and synchronisation, which can cause noticeable pauses in an application’s response. Similarly, there are effects from outside of the JVM at the operating system or hardware level that can cause an application to stall or become unresponsive because the JVM itself is no longer able to continue doing its work.
Which brings me to the third part of the title of this blog post: Myoclonic Jerks of the Diaphragm. According to Wikipedia, this is the technical term for a Hiccup, which is something that interrupts your ability to breathe. At Azul, we thought this was a good analogy for what happens to Java applications and so created jHiccup. Gil Tene, our CTO, wrote a blog post on How Java Got The Hiccups.
The concepts behind jHiccup are very simple:
- To minimise the observer effect jHiccup does not actually interact directly with your application code at all: it runs alongside it. Since it uses some of the resources of the machine it can’t eliminate the observer effect entirely, but to all intents and purposes, you can consider it to have zero performance impact.
- Again, to minimise the observer effect jHiccup spends most of its time asleep. To observe the effects of the whole system on an application, jHiccup sits in a loop that records the current time, sleeps for one millisecond (this value can be configured) and when it wakes up uses the new current time to calculate how much time (in nanoseconds) it was actually asleep.
- By recording the deltas to the intended amount of time asleep a histogram of the impact of all parts of the system (JVM, OS, HW, etc.) on the application can be generated. jHiccup also does a few other things like allocating objects to ensure that the JVM has at least some sort of workload.
Using jHiccup is extremely easy with three options for how to measure hiccups in your application:
- Use a supplied bash script and simply pass it your existing Java command line. If your application is started by running
java -Djava.library.path=/mylib -jar myApp.jarthen you just have to add jHiccup at the beginning, thus
jHiccup java -Djava.library.path=/mylib -jar myApp.jar
- For platforms that don’t support bash or where you want to run jHiccup directly, you can just add the jHiccup jar file as an agent. For our example that becomes
java –javaagent:jHiccup.jar -Djava.library.path=/mylib -jar myApp.jar
- To attach jHiccup to a running Java application use
jHiccup -p(since this uses the same bash script referenced in the first form the platform you’re using will need to support a bash interpreter).
I will soon be writing a follow-up blog post that will talk more about how to interpret and make use of the results of jHiccup.
To download JHiccup, click here.