Skip to main content

Garbage collector doesn't release memory.

2 replies [Last post]
Joined: 2008-05-13


We have an application that process a large amount of data once a day for 10/15 minutes on a redhat linux box using jse 1.5

Under normal operations during the day, less than 300MB is required to process data, however during the peak operations the memory required can go to 2GB.

This application runs on a server that is used by other applications so as to optimize server usage (we have distributed peak processing over time so the machine is more or less always busy).

What is preventing us from truly using the performance of the machine is that the jvm doesn't release the allocated memory, the application sticks at 2GB.

I would expect the GC to release partly the 2GB of RAM, especially as right after the 12 minutes of processing, jvm usage goes down to 300MB.

Simply put, instead of having 12 jvm at 300mb and one jvm at 2Gb we have 13 applications at 2gb, which isn't too great.

Any ideas?


ps: This is a follow up on a discussion at java one.

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Joined: 2004-01-07

By default the GC shrinks the commited amount of memory only, if after a collection less than 40% of the heap are used.

So, of course it will take until the next one of two full GCs until the heap will shink (maybe you can use it at the end of the heavy processing phase using System.gc()), but then less than 40% of the heap have to be used by java objects, otherwise the memory is not shirnked.

The defaults can be changed however, but use with care because it can destroy your performance:

lg Clemens

Joined: 2005-07-11

Yeah, what linuxhippy said ;-)

In addition, this may be one of those rare cases where calls to
System.gc() are justified. If you can pinpoint the spot in the code
where this high volume batch activity completes, then a couple of
calls to System.gc() might be enough to get the GC subsystem to
return the physical memory back to the system. You don't want
these calls to happen at an arbitrary time, though, as that would
likely destroy your overall performance outside this one event.

Note that calling System.gc() is a bit risky. First, the full gc event that
this causes might result in other performance issues, depending on the
point in time and the duration of the full gc's. Second, it's likely depending
on unspecified behavior of a JVM implementation - that is, it's relying on
the notion that the JVM will stop and wait for the System.gc() event to
complete. The docs indicate that a call to System.gc() is really just a
request, and that the JVM can decide how to interpret that request.
With HotSpot, it's typically a stop and wait type of event. However,
CMS in JDK 6 and later has the -XX:+ExplicitGCInvokesConcurrent
command line option that turns System.gc() calls into requests for a
CMS cycle. Any return of memory might not happen for a while after
you make the request.

And since I mentioned CMS, you might want to give it a try. It will
release memory to the OS at the end of a CMS cycle instead of on
full gc boundaries. This too might work to your advantage, but again
it's an implementation specific solution.

The only other thought I have is to fork/exec a new java process to
handle this load. This assumes that the overhead of the fork/exec
and the subsequent startup time of the target JVM doesn't cause it's
own problems. When the load spike is complete, just exit the app and
the memory resources will certainly be freed. The advantage to this
approach is that you are not relying of unspecified JVM behaviours.