Does GC release back memory to OS?

2019-01-01 09:38发布

问题:

When the garbage collector runs and releases memory does this memory go back to the OS or is it being kept as part of the process. I was under the strong impression that the memory is never actually released back to OS but kept as part of the memory area/pool to be reused by the same process.

As a result the actual memory of a process would never decrease. An article that reminded me was this and Java’s Runtime is written in C/C++ so I guess the same thing applies?

Update
My question is about Java. I am mentioning C/C++ since I assume the Java’s allocation/deallocation is done by JRE using some form of malloc/delete

回答1:

The HotSpot JVM does release memory back to the OS, but does so reluctantly since resizing the heap is expensive and it is assumed that if you needed that heap once you\'ll need it again.

You can make it more aggressive by setting -XX:GCTimeRatio=19 -XX:MinHeapFreeRatio=20 -XX:MaxHeapFreeRatio=30 which will allow it to spend more CPU time on collecting and constrain the amount of allocated-but-unused heap memory after a GC cycle.

Assuming you\'re using a concurrent collector you can also set -XX:InitiatingHeapOccupancyPercent=N with N to some low value to let the GC run concurrent collections almost continuously, which will consume even more CPU cycles but shrink the heap sooner. This generally is not a good idea, but on some types of machines with lots of spare CPU cores but short on memory it can make sense.

If you\'re using a collector with a default pause time goal (CMS or G1) you can also relax that goal to place fewer constraints on the collector, or you can switch go the parallel collector to prioritize footprint over pause times.

Additionally with Java 9 -XX:-ShrinkHeapInSteps option can be be used to apply the shrinking caused by the previous two options more aggressively. Relevant OpenJDK bug.

Do note that shrinking ability and behavior depends on the chosen garbage collector. For example G1 only gained the ability to yield back unused chunks in the middle of the heap with jdk8u20.

So if heap shrinking is needed it should be tested for a particular JVM version and GC configuration.

GC Logging with PrintAdaptiveSizePolicy may also provide insight, e.g. when the JVM tries to use more memory for the young generation to meet some goals.

There also is a draft JEP to have G1 yield back memory more eagerly, but being a draft it is uncertain if and when it will be implemented. It also mentions Shenandoah and the OpenJ9 VM having the ability.



回答2:

The JVM does release back memory under some circumstances, but (for performance reasons) this does not happen whenever some memory is garbage collected. It also depends on the JVM, OS, garbage collector etc. You can watch the memory consumption of your app with JConsole, VisualVM or another profiler.

Also see this related bug report



回答3:

this article here explains how the GC work in Java 7. In a nutshell, there are many different garbage collectors available. Usually the memory is kept for the Java process and only some GCs release it to the system (upon request I think). But, the memory used by the Java process will not grow indefinitely, as there is an upper limit defined by the Xmx option (which is 256m usually, but I think it is OS/machine dependant).



回答4:

If you use the G1 collector and call System.gc() occasionally (I do it once a minute), Java will reliably shrink the heap and give memory back to the OS.

Some people foam at the mouth whenever you even mention the idea of manually invoking the garbage collector - but you need to do that if you want reliable heap compaction.

I recommend using these options combined with the above suggestion for a very compact resident process size:

-XX:+UseG1GC -XX:MaxHeapFreeRatio=30 -XX:MinHeapFreeRatio=10

Been using these options daily for months with a big application (a whole Java-based guest OS) with dynamically loading and unloading classes - and the Java process almost always stays between 400 and 800 MB.