Most people don't know what RMI DGC is. And most people don't need to know what RMI DGC is. However, if you run JBoss Application Server on Sun's VM, RMI DGC is probably sucking the performance out of your app. Whether you use RMI or do not use RMI, JBAS causes RMI to be loaded. By default, the RMI subsystem forces a full garbage collection once per minute. This means that all threads are paused and the entire heap is scanned. This takes a good while, especially under load. To change this behavior to once per hour edit your $JBOSS_HOME/bin/run.conf as follows:
# Specify options to pass to the Java VM.
if [ "x$JAVA_OPTS" = "x" ]; then
JAVA_OPTS="-server -Xms128m -Xmx128m \
The \ characters above are intended to be line continuations rather than literals (so don't put them, just put it all on the same line if you like). Obviously if you changed the heap size then the above -X params will be larger. I've changed the startup script in the 4.0 branch and head so in the future releases you won't need to do this manually.
The System.gc() call that the spec says may not do anything or may do something actually triggers this full garbage collection. You probably don't want any code doing that (including the RMI DGC) so rather than the above you can add XX:+DisableExplicitGC and never have forced full GCs. By default you will still see a full GC (in Sun's VM) once the heap reaches approximately 70% utilization (the ratio is configurable).
So when do you need this default RMI DGC full GC behavior? Approximately never, but if you do a lot of remote object calls (EJBs) and don't cache your Home or Remote objects then MAYBE once per hour won't be enough. For more of these tidbits read Tuning Garbage Collection with the 1.4.2 Java[tm] Virtual Machine. If you DON'T want to become a GC expert (especially if you have a multi-processor machine) then you probably should upgrade to JDK 5 as it will pick more sensible defaults for your platform. (JRockit or Sun recommended. IBM's VM is pretty buggy and has a retro garbage collector.) For JDK 1.4.2, JRockit already tries to autotune. Sun JDK 1.4.2 defaults to a single threaded generational but slow GC.
What other semi-mornic defaults lurk to find you? Well one of my favorite is the default thread stack size when you throw on the "-server" switch. If you've been using Java for awhile then you may remember running out of stack space in JDK 1.x. That's because the default was something like 16k. Well today's systems have a default that is much higher -- in fact on most platforms "-server" means 512k stack per thread in 32bit mode and a whopping 1MB per thread in 64 bit mode. Since this is allocated OUTSIDE the heap, lets think about what that means... Assuming I've set my VM to 1.3g on 32-bit Linux w/o large memory pages enabled -- I've got about 700MB to play with. In any large app, 128M of this is probably going to Perm space (where my class definitions are compiled) which leaves 572M. Take maybe 100MB for "stuff" and we have 472M. So 472M is about 944 threads. Which sounds like a lot and is probably an overestimate (or 100MB for "stuff" was an under estimate), but in large systems 944 threads can be eaten up quickly especially with thread pools (Tomcat alone is probably holding onto 300 of these by default). Unless massively cyclical recursion is your favorite way to write business code, 0.5MB per thread is probably a bit big. On Linux you seem to get a plain OutOfMemoryError. On Solaris (4G max process space with 32bit vm) you get "cannot create native thread" plus an OOME. Change this by passing "-XX:ThreadStackSize=128" or if that isn't available on your platform then "-Xss128k" may do the trick by itself (generally it can only set the number higher and not lower). Test this of course, you may need more than 128k (256k is a nice conservative number).
So there is a lot more to be done about VM tuning in any large app, but these two sets of switches consitute the "go fast" button and the "please work" button respectively. Maybe next time we'll talk parallel and concurrent GC or why IBM's VM is yucky and JRockit is goodness. Until then, just remember that Sun JDK 5's parallel and concurrent GC are much more stable than 1.42's and upgrade if you haven't already.