For memory optimization reasons, I'm launching myself the garbage collector during profiling, to check if objects are correctly cleaned after disposing of them.
The call to garbage collector is not enough, though, and it seems that there is no guarantee of what it will clean.
Is there a way to call it, to be sure it will recover as much as it can, in profiling conditions (this would have no point in production, of course)? Or is "calling it several times" the only way to be "almost sure"?
Or did I simply misunderstand something about the Garbage Collector?
In all generality, a "complete garbage collection" is ill-defined. The GC detects unreachable objects, and reclaim them. It so happens that most GC implementations operate on a "cycle" basis, and once a complete cycle has run, it is possible to define an sound notion of "reclaimed space". Therefore, if you can run a full cycle and that cycle has found no reclaimable space at all, and the application is otherwise "idle" (e.g. not updating pointers), then you could say that you have temporarily reached a "fully collected" point.
Thus, you may want to do something like that:
Runtime r = Runtime.getRuntime();
r.gc();
long f = r.freeMemory();
long m = r.maxMemory();
long t = r.totalMemory();
for (;;) {
r.gc();
long f2 = r.freeMemory();
long m2 = r.maxMemory();
long t2 = r.totalMemory();
if (f == f2 && m == m2 && t == t2)
break;
f = f2;
m = m2;
t = t2;
}
System.out.println("Full GC achieved.");
This code relies on some assumptions, foremost of which being that Runtime.gc()
is more than a "hint", and really forces some GC activity. Sun's JVM can be launched with the "-XX:-DisableExplicitGC" flag, which transforms Runtime.gc()
into a no-op, effectively preventing the code above from doing anything.
There are a few caveats as well:
A JVM may have some background continuous activity, e.g. Timer
threads. Some of that activity may be "hidden", i.e. not code written by the application developer. Also, think of the AWT / Swing event-dispatcher thread.
A GC run may trigger extra asynchronous activity, through finalizable objects or soft/weak/phantom references. Such activity is necessarily asynchronous and may run for unbounded amounts of time. Runtime.gc()
will not wait for that to finish. It is actually a matter of definition: do you consider the GC to be "complete" if the finalizers and reference queues have not yet been processed ?
Nothing really forces the code above to terminate...
For a "more complete" GC, you may use the JVMTI interface (the one used by debuggers) which allows you to run the GC but also to pause the target JVM threads, which makes it much easier to define and achieve a "complete GC" state.
Forcibly allocate the max amount of memory available. When JVM is on corner of OutOfMemoryError
it's forced to run the GC.
byte[] boom = new byte[512 * 1024 * 1024]; // Assuming 512MB
Obviously for pure testing reasons :)
Another option is to use a better profiler. The one which gives better reports about memory usage and GC eligible objects.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With