Is it possible to force garbage collection in Java, even if it is tricky to do? I know about System.gc();
and Runtime.gc();
but they only suggest to do GC. How can I force GC?
23 Answers
Your best option is to call System.gc()
which simply is a hint to the garbage collector that you want it to do a collection. There is no way to force and immediate collection though as the garbage collector is non-deterministic.
The jlibs library has a good utility class for garbage collection. You can force garbage collection using a nifty little trick with WeakReference objects.
RuntimeUtil.gc() from the jlibs:
/**
* This method guarantees that garbage collection is
* done unlike <code>{@link System#gc()}</code>
*/
public static void gc() {
Object obj = new Object();
WeakReference ref = new WeakReference<Object>(obj);
obj = null;
while(ref.get() != null) {
System.gc();
}
}
Using the Java™ Virtual Machine Tool Interface (JVM TI), the function
jvmtiError ForceGarbageCollection(jvmtiEnv* env)
will "Force the VM to perform a garbage collection." The JVM TI is part of the JavaTM Platform Debugger Architecture (JPDA).
YES it is almost possible to forced you have to call to methods in the same order and at the same time this ones are:
System.gc ();
System.runFinalization ();
even if is just one object to clean the use of this two methods at the same time force the garbage collector to use the finalise()
method of unreachable object freeing the memory assigned and doing what the finalize()
method states.
HOWEVER it is a terrible practice to use the garbage collector because the use of it could introduce an over load to the software that may be even worst than on the memory, the garbage collector has his own thread which is not possible to control plus depending on the algorithm used by the gc could take more time and is consider very inefficient, you should check your software if it worst with the help of the gc because it is definitely broke, a good solution must not depend on the gc.
NOTE: just to keep on mind this will works only if in the finalize method is not a reassignment of the object, if this happens the object will keep alive an it will have a resurrection which is technically possible.
Under the documentation for OutOfMemoryError it declares that it will not be thrown unless the VM has failed to reclaim memory following a full garbage collection. So if you keep allocating memory until you get the error, you will have already forced a full garbage collection.
Presumably the question you really wanted to ask was "how can I reclaim the memory I think I should be reclaiming by garbage collection?"
.gc is a candidate for elimination in future releases - a Sun Engineer once commented that maybe fewer than twenty people in the world actually know how to use .gc() - I did some work last night for a few hours on a central / critical data-structure using SecureRandom generated data, at somewhere just past 40,000 objects the vm would slow down as though it had run out of pointers. Clearly it was choking down on 16-bit pointer tables and exhibited classic "failing machinery" behavior.
I tried -Xms and so on, kept bit twiddling until it would run to about 57,xxx something. Then it would run gc going from say 57,127 to 57,128 after a gc() - at about the pace of code-bloat at camp Easy Money.
Your design needs fundamental re-work, probably a sliding window approach.
JVM specification doesn't say anything specific about garbage collection. Due to this, vendors are free to implement GC in their way.
So this vagueness causes uncertainty in garbage collection behavior. You should check your JVM details to know about the garbage collection approaches/algorithms. Also there are options to customize behavior as well.
How to Force Java GC
Okay, here are a few different ways to force Java GC.
- Click JConsole's
Perform GC
button - Use JMap's
jmap -histo:live 7544
command where 7544 is the pid - Call the Java Diagnostic Console's
jcmd 7544 GC.run
command - Call
System.gc();
in your code - Call
Runtime.getRuntime().gc()
; in your code
None of these work
Here's the dirty little secret. None of these are guaranteed to work. You really can't force Java GC.
The Java garbage collection algos are non-deterministic, and while all of these methods can motivate the JVM to do GC, you can't actually force it. If the JVM has too much going on and a stop-the-world operation is not possible, these commands will either error out, or they will run but GC won't actually happen.
if (input.equalsIgnoreCase("gc")) {
System.gc();
result = "Just some GC.";
}
if (input.equalsIgnoreCase("runtime")) {
Runtime.getRuntime().gc();
result = "Just some more GC.";
}
Fix the darn problem
If you've got a memory leak or object allocation problem, then fix it. Sitting around with your finger on Java Mission Control's Force Java GC
button only kicks the can down the road. Profile your app with Java Flight Recorder, view the results in VisualVM or JMC, and fix the problem. Trying to force Java GC is a fools game.
If you need to force garbage collection, perhaps you should consider how you're managing resources. Are you creating large objects that persist in memory? Are you creating large objects (e.g., graphics classes) that have a Disposable
interface and not calling dispose()
when done with it? Are you declaring something at a class level that you only need within a single method?
It would be better if you would describe the reason why you need garbage collection. If you are using SWT, you can dispose resources such as Image
and Font
to free memory. For instance:
Image img = new Image(Display.getDefault(), 16, 16);
img.dispose();
There are also tools to determine undisposed resources.
Another options is to not create new objects.
Object pooling is away to reduce the need GC in Java.
Object pooling is generally not going to be faster than Object creation (esp for lightweight objects) but it is faster than Garbage Collection. If you created 10,000 objects and each object was 16 bytes. That's 160,000 bytes GC has to reclaim. On the other hand, if you don't need all 10,000 at the same time, you can create a pool to recycle/reuse the objects which eliminates the need to construct new objects and eliminates the need to GC old objects.
Something like this (untested). And if you want it to be thread safe you can swap out the LinkedList for a ConcurrentLinkedQueue.
public abstract class Pool<T> {
private int mApproximateSize;
private LinkedList<T> mPool = new LinkedList<>();
public Pool(int approximateSize) {
mApproximateSize = approximateSize;
}
public T attain() {
T item = mPool.poll();
if (item == null) {
item = newInstance();
}
return item;
}
public void release(T item) {
int approxSize = mPool.size(); // not guaranteed accurate
if (approxSize < mApproximateSize) {
recycle(item);
mPool.add(item);
} else if (approxSize > mApproximateSize) {
decommission(mPool.poll());
}
}
public abstract T newInstance();
public abstract void recycle(T item);
public void decommission(T item) { }
}
We can trigger jmap -histo:live <pid>
using the java runtime. This will force a full GC on heap to mark all the live objects.
public static void triggerFullGC() throws IOException, InterruptedException {
String pid = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
Process process = Runtime.getRuntime().exec(
String.format("jmap -histo:live %s", pid)
);
System.out.println("Process completed with exit code :" + process.waitFor());
}
If you are running out of memory and getting an OutOfMemoryException
you can try increasing the amount of heap space available to java by starting you program with java -Xms128m -Xmx512m
instead of just java
. This will give you an initial heap size of 128Mb and a maximum of 512Mb, which is far more than the standard 32Mb/128Mb.
Really, I don't get you. But to be clear about "Infinite Object Creation" I meant that there is some piece of code at my big system do creation of objects whom handles and alive in memory, I could not get this piece of code actually, just gesture!!
This is correct, only gesture. You have pretty much the standard answers already given by several posters. Let's take this one by one:
- I could not get this piece of code actually
Correct, there is no actual jvm - such is only a specification, a bunch of computer science describing a desired behaviour ... I recently dug into initializing Java objects from native code. To get what you want, the only way is to do what is called aggressive nulling. The mistakes if done wrong are so bad doing that we have to limit ourselves to the original scope of the question:
- some piece of code at my big system do creation of objects
Most of the posters here will assume you are saying you are working to an interface, if such we would have to see if you are being handed the entire object or one item at a time.
If you no longer need an object, you can assign null to the object but if you get it wrong there is a null pointer exception generated. I bet you can achieve better work if you use NIO
Any time you or I or anyone else gets: "Please I need that horribly." it is almost universal precursor to near total destruction of what you are trying to work on .... write us a small sample code, sanitizing from it any actual code used and show us your question.
Do not get frustrated. Often what this resolves to is your dba is using a package bought somewhere and the original design is not tweaked for massive data structures.
That is very common.
There is some indirect way for forcing garbage collector. You just need to fill heap with temporary objects until the point when garbage collector will execute. I've made class which forces garbage collector in this way:
class GarbageCollectorManager {
private static boolean collectionWasForced;
private static int refCounter = 0;
public GarbageCollectorManager() {
refCounter++;
}
@Override
protected void finalize() {
try {
collectionWasForced = true;
refCounter--;
super.finalize();
} catch (Throwable ex) {
Logger.getLogger(GarbageCollectorManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
public int forceGarbageCollection() {
final int TEMPORARY_ARRAY_SIZE_FOR_GC = 200_000;
int iterationsUntilCollected = 0;
collectionWasForced = false;
if (refCounter < 2)
new GarbageCollectorManager();
while (!collectionWasForced) {
iterationsUntilCollected++;
int[] arr = new int[TEMPORARY_ARRAY_SIZE_FOR_GC];
arr = null;
}
return iterationsUntilCollected;
}
}
Usage:
GarbageCollectorManager manager = new GarbageCollectorManager();
int iterationsUntilGcExecuted = manager.forceGarbageCollection();
I don't know how much this method is useful, because it fills heap constantly, but if you have mission critical application which MUST force GC - when this may be the Java portable way to force GC.
I would like to add some thing here. Please not that Java runs on Virtual Machine and not actual Machine. The virtual machine has its own way of communication with the machine. It may varry from system to system. Now When we call the GC we ask the Virtual Machine of Java to call the Garbage Collector.
Since the Garbage Collector is with Virtual Machine , we can not force it to do a cleanup there and then. Rather that we queue our request with the Garbage Collector. It depends on the Virtual Machine, after particular time (this may change from system to system, generally when the threshold memory allocated to the JVM is full) the actual machine will free up the space. :D
On OracleJDK 10 with G1 GC, a single call to System.gc()
will cause GC to clean up the Old Collection. I am not sure if GC runs immediately. However, GC will not clean up the Young Collection even if System.gc()
is called many times in a loop. To get GC to clean up the Young Collection, you must allocate in a loop (e.g. new byte[1024]
) without calling System.gc()
. Calling System.gc()
for some reason prevents GC from cleaning up the Young Collection.