G1 (-XX:+UseG1GC), Parallel scavenge (-XX:+UseParallelGC) and
ParallelOld (-XX:+UseParallelOldGC) do return memory when the heap
shrinks. I’m not so sure about Serial and CMS, they didn’t shrink
their heap in my experiments.Both parallel collectors do require a number of GCs before shrinking
the heap down to an “acceptable” size. This is per design. They are
deliberately holding on to the heap assuming that it will be needed in
the future. Setting the flag -XX:GCTimeRatio=1 will improve the
situation somewhat but it will still take several GCs to shrink a lot.G1 is remarkably good at shrinking the heap fast, so for the usecase
described above I would say it’s solvable by using G1 and running
System.gc()
after having released all caches and class loaders etc.
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6498735