I am building a Java web app, using the Play! Framework. I’m hosting it on playapps.net. I have been puzzling for a while over the provided graphs of memory consumption. Here is a sample:

The graph comes from a period of consistent but nominal activity. I did nothing to trigger the falloff in memory, so I presume this occurred because the garbage collector ran as it has almost reached its allowable memory consumption.
My questions:
- Is it fair for me to assume that my application does not have a memory leak, as it appears that all the memory is correctly reclaimed by the garbage collector when it does run?
- (from the title) Why is java waiting until the last possible second to run the garbage collector? I am seeing significant performance degradation as the memory consumption grows to the top fourth of the graph.
- If my assertions above are correct, then how can I go about fixing this issue? The other posts I have read on SO seem opposed to calls to
System.gc(), ranging from neutral (“it’s only a request to run GC, so the JVM may just ignore you”) to outright opposed (“code that relies onSystem.gc()is fundamentally broken”). Or am I off base here, and I should be looking for defects in my own code that is causing this behavior and intermittent performance loss?
UPDATE
I have opened a discussion on PlayApps.net pointing to this question and mentioning some of the points here; specifically @Affe’s comment regarding the settings for a full GC being set very conservatively, and @G_H’s comment about settings for the initial and max heap size.
Here’s a link to the discussion, though you unfortunately need a playapps account to view it.
I will report the feedback here when I get it; thanks so much everyone for your answers, I’ve already learned a great deal from them!
Resolution
Playapps support, which is still great, didn’t have many suggestions for me, their only thought being that if I was using the cache extensively this may be keeping objects alive longer than need be, but that isn’t the case. I still learned a ton (woo hoo!), and I gave @Ryan Amos the green check as I took his suggestion of calling System.gc() every half day, which for now is working fine.
Java won’t run the garbage cleaner until it has to, because the garbage cleaner slows things down quite a bit and shouldn’t be run that frequently. I think you would be OK to schedule a cleaning more frequently, such as every 3 hours. If an application never consumes full memory, there should be no reason to ever run the garbage cleaner, which is why Java only runs it when the memory is very high.
So basically, don’t worry about what others say: do what works best. If you find performance improvements from running the garbage cleaner at 66% memory, do it.