Search code examples
javagarbage-collectionjvmjvm-hotspot

What causes the JVM to do a major garbage collection?


I have a Java app which shows different GC behaviors in different environments. In one environment, the heap usage graph is a slow sawtooth with major GCs every 10 hours or so, only when the heap is >90% full. In another environment, the JVM does major GCs every hour on the dot (the heap is normally between 10% and 30% at these times).

My question is, what are the factors which cause the JVM to decide to do a major GC?

Obviously it collects when the heap is nearly full, but there is some other cause at play which I am guessing is related to an hourly scheduled task within my app (although there is no spike in memory usage at this time).

I assume GC behaviour depends heavily on the JVM; I am using:

  • Java HotSpot(TM) 64-Bit Server VM 1.7.0_21 Oracle Corporation
  • No specific GC options, so using the default settings for 64-bit server (PS MarkSweep and PS Scavenge)

Other info:

  • This is a web app running in Tomcat 6.
  • Perm gen hovers around 10% in both environments.
  • The environment with the sawtooth behaviour has 7Gb max heap, the other has 14Gb.

Please, no guesswork. The JVM must have rules for deciding when to perform a major GC, and these rules must be encoded deep in the source somewhere. If anyone knows what they are, or where they are documented, please share!


Solution

  • Garbage collection is a pretty complicated topic, and while you could learn all the details about this, I think what’s happening in your case is pretty simple.

    Sun’s Garbage Collection Tuning guide, under the “Explicit Garbage Collection” heading, warns:

    applications can interact with garbage collection … by invoking full garbage collections explicitly … This can force a major collection to be done when it may not be necessary … One of the most commonly encountered uses of explicit garbage collection occurs with RMI … RMI forces full collections periodically

    That guide says that the default time between garbage collections is one minute, but the sun.rmi Properties reference, under sun.rmi.dgc.server.gcInterval says:

    The default value is 3600000 milliseconds (one hour).

    If you’re seeing major collections every hour in one application but not another, it’s probably because the application is using RMI, possibly only internally, and you haven’t added -XX:+DisableExplicitGC to the startup flags.

    Disable explicit GC, or test this hypothesis by setting -Dsun.rmi.dgc.server.gcInterval=7200000 and observing if GCs happen every two hours instead.