views:

155

answers:

4

I've got a program that runs very happily with -Xmx2g. With -Xmx1g, it grinds to a halt. It never gets an out of memory exception -- or, at least, I've never had the patience to wait long enough.

This suggests that the total footprint does fit into 1g, but that the GC has some anxiety about possibly running out of space.

The memory footprint is a combination of some large, stable, items with a good deal of ephemeral traffic.

Are any of the more-or-less obscure GC options relevant to this situation?

+3  A: 

There are a bunch of options you can set on the JVM for garbage collection with http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html. When an app grinds to a halt due to GC, you're usually seeing a lot of major collects, which can stop everything when being collected. You can tune the minor and major collect parameters to see if you can have more frequent minor collections.

I recommend taking a look at what is eating up the heap using a tool like VisualVM (shipped with JDK6, I believe update 7+) and analyze the object graphs. Also look at tools for analyzing an hprof file (http://stackoverflow.com/questions/185893/how-do-i-analyze-a-hprof-file).

Jeff Storey
+2  A: 

It can take a really long time for an OOME in many cases. This is because, when the GC begins working hard, it stops all activity in your program. If you normally get, say, 1 second of useful program time for every 0.01s of GC time, in these cases you may see it totally reversed -- 0.01s of useful program time for every 1s of GC time. At this rate, it can take a ridiculously long time to eat up the last 512k of a 1 GB heap.

VisualVM and its VisualGC plugin are your friends; their graphs will show distinct patterns when you're in this sort of state.

Matt McHenry
+2  A: 

It sounds like you have not given the JVM enough heap. Sure, the working set may fit in 1Gbytes, but you still need to give it more. To understand why, read on.

Let us assume that when a garbage collector runs, it does an amount of work W1 that is proportional to the amount of non-garbage that it scans in order to identify the garbage and another amount of work W2 that is proportional to the amount of garbage that it finds. (In fact, it is a bit more complicated than this ... but lets keep the analysis simple.)

Suppose that you have a heap 1Gb heap with 0.9Gb occupied. Each time the GC runs, it can reclaim at most 0.1Gb of the heap space, and in doing so it needs to do W1 * 0.9Gb + W2 * 0.1Gb of work. The amount of work per byte reclaimed is (W1 * 0.9Gb + W2 * 0.1Gb) / 0.1Gb; i.e. 9 * W1 + W2.

Now suppose that you have a 2Gb heap with 0.9Gb occupied. Now the amount of work per byte reclaimed is (W1 * 0.9Gb + W2 * 1.1Gb) / 1.1Gb or W1 * 9/11 + W2.

If you compare these two, you will see that the GC does roughly W1 * 8 more work per byte reclaimed in the 1Gb heap compared to the 2Gb heap.

As a general rule the closer to full you run the heap, the more inefficient the garbage collector is going to be. The lessons are:

  • configure the JVM to use a generous heap, and

  • configure the JVM to throw an OOM if there is less than (say) 25% of the heap free after running a full GC.

Stephen C
just cannot resist to upvote your efford
stacker
A: 

If you wan't to do some fine tuning you should check the MinHeapFreeRatio and MaxHeapFreeRatio parameters among others desribed here Java SE 6 HotSpot[tm] Virtual Machine Garbage Collection Tuning this sould lead to the "tranquillizer effect".

stacker