5 things you didn't know about ... Command-line flags for the JVM

Fine-tune JVM performance and the Java runtime

Java™ virtual machines come with hundreds of command-line options, which more experienced Java developers can use to tune the Java runtime. Learn how to monitor and log compiler performance, disable explicit garbage collection (System.gc();), extend the JRE, and more.

Ted Neward, Principal, Neward & Associates

Ted Neward photoTed Neward is the principal of Neward & Associates, where he consults, mentors, teaches, and presents on Java, .NET, XML Services, and other platforms. He resides near Seattle, Washington.



24 August 2010

Also available in Chinese Russian Japanese Portuguese

About this series

So you think you know about Java programming? The fact is, most developers scratch the surface of the Java platform, learning just enough to get the job done. In this series, Ted Neward digs beneath the core functionality of the Java platform to uncover little-known facts that could help you solve even the stickiest programming challenges.

The JVM is the workhorse behind the Java application functionality and performance that most Java developers take for granted. And yet very few of us truly understand how the JVM does what it does — things like allocating and garbage-collecting objects, spinning up threads, opening and closing files, interpreting and/or JIT-compiling Java bytecode, and more.

Not only does unfamiliarity with the JVM cost you in terms of application performance, but when something goes wrong with the JVM, it can be very difficult to try to fix.

This installment of the 5 things series introduces a handful of command-line JVM flags that you can use to diagnose and tune the performance of your Java virtual machine.

1. DisableExplicitGC

Develop skills on this topic

This content is part of a progressive knowledge path for advancing your skills. See Become a Java developer

I can't tell you how many times I've been asked to consult on an application performance problem, done a quick grep across the code, and found what's shown in Listing 1 — the original Java performance antipattern:

Listing 1. System.gc();
// We just released a bunch of objects, so tell the stupid
// garbage collector to collect them already!
System.gc();

Explicit garbage collection is a really bad idea— something on the order of locking yourself in a phone booth with a rabid pit bull. Although the exact semantics of the call are implementation-dependent, assuming your JVM is running a generational garbage collector (which most of them are), System.gc(); forces the VM to do a "full sweep" of the heap, even if one isn't necessary. Full sweeps are typically several orders of magnitude more expensive than a regular GC operation, which is just plain bad math.

But don't take my word for it — Sun's engineers provided us with a JVM flag for just this particular human-error problem: The -XX:+DisableExplicitGC flag automatically turns a System.gc() call into a no-op, giving you the opportunity to run your code and see for yourself whether System.gc() has helped or harmed the overall execution of the JVM.

The same function that is provided on the HotSpot technology based JVMs can be achieved using the -Xdisableexplicitgc output on the IBM JVMs.


2. HeapDumpOnOutOfMemoryError

Have you ever had one of those days where the JVM kept dying on you, throwing OutOfMemoryErrors, and you couldn't for the life of you set up the debugger to catch it and see what the problem was? Sporadic and/or nondeterministic problems like this can drive a developer completely insane.

Caveat emptor

Not all command-line flags are necessarily supported by any VM other than the one from Sun/Oracle. The best way to find out whether a flag is supported is, of course, to try it and see if it works. Given that these flags are technically unsupported, however, you take full responsibility for using them. Neither I nor Sun/Oracle nor IBM® will be held accountable if any of these flags causes your code, your data, your server, or your mother to evaporate into thin air. As a precaution, I advise exercising them first in a virtual (non-production) environment.

What you want at times like these is to catch a snapshot of the heap right as the JVM is on its dying breath — and that's precisely what the -XX:+HeapDumpOnOutOfMemoryError command does.

Running this command tells the JVM to take a "heap dump snapshot" and save it to a file for processing, usually using the jhat utility (which I introduced in a previous article). You can specify the actual path to which the file is saved using the corresponding -XX:HeapDumpPath flag. (Regardless of where the file is saved, make sure the filesystem and/or the Java process has the necessary permission configuration to be able to write there.)

The IBM JVMs dump engine has this facility enabled by default, ensuring that you obtain a heapdump if an OutOfMemoryError occurs. The IBM dump engine provides a number of configuration options using the -Xdump command line options, including disabling the dumps.


3. bootclasspath

Periodically, it's useful to slip a class into the classpath that is slightly different from the one that comes with the stock JRE, or that somehow extends the JRE. (An example would be a new Java Crypto API provider). If you want to extend the JRE, then your custom implementation needs to be available to the bootstrap ClassLoader, which loads java.lang.Object and all his buddies in rt.jar.

While you could crack open rt.jar and slide your custom implementation or new package into it, that would technically violate the license you agreed to when you downloaded the JDK.

Instead, use the JVM's own -Xbootclasspath option, along with its kin, -Xbootclasspath/p and -Xbootclasspath/a.

-Xbootclasspath lets you set the complete boot classpath, which typically has to include a reference to rt.jar, plus a bunch of other JAR files that ship with the JDK that aren't part of rt.jar. -Xbootclasspath/p prepends the value to the existing bootclasspath, and -Xbootclasspath/a appends it.

If, for instance, you've modified the stock java.lang.Integer, and put the modifications in a subdirectory, mods, then a -Xbootclasspath/a mods parameter will put the new Integer in front of the default one.


4. verbose

-verbose is a useful first-level diagnostic utility for virtually any type of Java application. The flag has three sub-flags: gc, class, and jni.

gc, is typically the first place developers go to try to figure out if the JVM garbage collector is acting up and causing poor performance. Unfortunately, interpreting gc's output can be tricky — enough so that it's been the subject of whole books. What's worse, the output printed to the command-line can change from one Java release to another, or from one JVM to another, making it even harder to correctly interpret.

Generally speaking, if the garbage collector is a generational collector (which most of the "enterprise-class" VMs are), some kind of visible flag will appear to indicate a full-sweep GC pass; in the Sun JVM, the flag appears as "[Full GC ...]" at the start of the GC output line.

class can be a life-saver for trying to diagnose ClassLoader and/or mismatched class conflicts. It reports not only when a class is loaded, but also where the class was loaded from, including the path to the JAR file, assuming it came from a JAR.

jni is of little use except when working with JNI and native libraries. When turned on, it will report various JNI events, such as when native libraries are loaded and methods are bound; again, the output can vary from one release or JVM to another.


5. Command-line -X

I've listed some of my favorite command-line options that the JVM provides, but there are so many more that you could discover on your own. Running the command-line argument -X lists all the non-standard (but mostly safe) arguments that the JVM provides — things like:

  • -Xint, which runs the JVM in interpreted mode (which can be useful for testing whether the JIT compiler is actually having an effect on your code or verifying if you have a bug in the JIT compiler).
  • -Xloggc:, which does the same thing as -verbose:gc but logs to a file instead of spewing to the command-line window.

JVM command-line options change from time to time, so periodically having a look is a good idea. It could even mean the difference between a late night spent glowering at your monitor, or going home at 5 p.m. to a lovely dinner with the spouse and kids (or slaughtering your enemies in Mass Effect 2, depending on your preference).

Logging of verbose:gc output to file is requested using the -Xverbosegclog option on the IBM JVMs, which also allows the specification of rolling log file generation.


In conclusion

Command-line flags aren't intended for permanent use in a production environment — in fact, aside from the flags that you (might) end up using to tune the JVM garbage collector, no non-standard command-line flags are really intended for production use. But as tools to peer into the inner workings of the otherwise completely opaque virtual machine, they are invaluable.

Next up in the 5 things series: Everyday Java tools.

Resources

Learn

Discuss

  • Get involved in the My developerWorks community. Connect with other developerWorks users while exploring the developer-driven blogs, forums, groups, and wikis.

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Java technology on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Java technology, Open source
ArticleID=512456
ArticleTitle=5 things you didn't know about ... Command-line flags for the JVM
publish-date=08242010