Reputation: 24447
With the System.gc()
method it is possible to force a full GC run. This is very expensive. Is there an option to force the first generation GC only? My application is currently running on Java 11. I am thinking of something like MemoryPoolMXBean
.
Background: I want to start a large memory consuming task and if the free memory is lower than the needed memory then I want to know if I can start it without risk or should I try it later or swap cache to the disk. In real I want to know the free memory after such first GC. Our analysis shows that this will be enough in most cases (>99%).
Upvotes: 0
Views: 415
Reputation: 24447
I use the follow code to check if there are enough memory for the memory intentive operation:
int requiredMemory = ...;
// force a first generation GC
try {
byte[] ram = new byte[requiredMemory];
requiredMemory = ram[0]; // should be ever 0 and prevent optimize through JIT because the allocated array works outside of the block
} catch( OutOfMemoryError ex ) {
// ignore, uncritical because it occur through a large block
}
if( requiredMemory == 0 ) {
...
}
Upvotes: 0
Reputation: 718946
The short answer is that there is no supported way to do this. It is System.gc()
or nothing.
Longer answer:
I trawled the JVM source code and found the C++ CollectedHeap
API. (It is in "src/hotspot/share/gc/shared/collectedHeap.hpp" if you are interested.) This is the internal interface between the JVM's configured heap and the rest of the JVM.
It you look at this API, you can see the virtual methods that the JVM can call to trigger a garbage collection. It turns out that there are three of them, but they all invoke a full garbage collection. So even if you were to try to trigger a GC from native code invoked using JNI, you would stull end up doing a full GC.
It would be possible to download the OpenJDK source code, modify the CollectedHeap
API and the heap implementations so that you could trigger a new generation GC, and build a custom JVM with the functionality that you require. You could even distribute the binaries provided that you abided by the terms of the OpenJDK "GPLv2 + Classpath exception" license. However, that would be a huge undertaking.
But I think your question is misguided.
Triggering a GC is almost always a bad idea. As a general rule, the heap itself knows the best (most efficient) time to run a GC in order to meet the goals that you have configured in the GC tuning options. The best strategy is to not interfere. Just let the JVM take care of the timing.
The fundamental issue is that most of the cost of a gc()
run is taken in dealing with the non-garbage objects; i.e. the objects that need to be copied from one space to another by the collector. Any garbage that is left behind will (typically) just be zeroed. So the most ergonomic time to run a collection is when the ratio of garbage to non-garbage (in the space being collected) is as high as possible; i.e. when it is close to full.
The only plausibly good reason to interfere (by calling System.gc()
) in production code is if the application has points where it knows that it is OK to be inefficient. A classic example is a game where GC pauses are harmful during normal play, but they are OK when (for example) loading the next "level". So triggering the GC after loading a level could be beneficial.
It is not clear from your question and comments what you are aiming to achieve by forcing the GC to run. But my advice is to read up on Java GC tuning, set the JVM options, and then leave it to the JVM to manage the heap.
Upvotes: 1