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?
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.