When Does System.Gc() Do Something

java -> System.gc(); Does this call opens a new Thread or not?

The exact behavior here depends entirely on the JVM implementation. In spec (that is what a proper JVM implementation needs to provide you), it can happen in parallel, it can happen first before your code executes, or it can not happen at all.

In practice, my observation on JVMs I have happened to observe is that it runs immediately in a separate thread. However, in some cases multiple calls spawn multiple threads, sometimes it queues the requests on one thread. The Garbage collection launched was always a "stop-the-world" type (that is it was very complete and slowed or paused the application).

However, given your comment to @Chris Dail, your underlying problem isn't the behavior of a System.gc() call. Calling System.gc() can have some uses. It can be used clear memory so you can get a sense of how large the footprint of the application actually is currently. It can also be used as a strategy to ensure that a stop-the-world garbage collection happens earlier so that it "stops the world" for a shorter amount of time because there is less memory to clear. (I should note that as JVM's get more and more sophisticated this kind of thing is less and less necessary, and actually becomes counter-productive).

What it does not do however, is in any way solve an OutOfMemoryError. The JVM will not give you an OutOfMemoryError until it has garbage collected to the best of its ability. Calling System.gc does not change that. If you have an OutOfMemoryError it is likely because you are holding reference to objects in ways that you don't really need, but that are preventing those Objects memory from being reclaimed.

Why is it bad practice to call System.gc()?

The reason everyone always says to avoid System.gc() is that it is a pretty good indicator of fundamentally broken code. Any code that depends on it for correctness is certainly broken; any that rely on it for performance are most likely broken.

You don't know what sort of garbage collector you are running under. There are certainly some that do not "stop the world" as you assert, but some JVMs aren't that smart or for various reasons (perhaps they are on a phone?) don't do it. You don't know what it's going to do.

Also, it's not guaranteed to do anything. The JVM may just entirely ignore your request.

The combination of "you don't know what it will do," "you don't know if it will even help," and "you shouldn't need to call it anyway" are why people are so forceful in saying that generally you shouldn't call it. I think it's a case of "if you need to ask whether you should be using this, you shouldn't"


EDIT to address a few concerns from the other thread:

After reading the thread you linked, there's a few more things I'd like to point out.
First, someone suggested that calling gc() may return memory to the system. That's certainly not necessarily true - the Java heap itself grows independently of Java allocations.

As in, the JVM will hold memory (many tens of megabytes) and grow the heap as necessary. It doesn't necessarily return that memory to the system even when you free Java objects; it is perfectly free to hold on to the allocated memory to use for future Java allocations.

To show that it's possible that System.gc() does nothing, view
JDK bug 6668279
and in particular that there's a -XX:DisableExplicitGC VM option:

By default calls to System.gc() are enabled (-XX:-DisableExplicitGC). Use -XX:+DisableExplicitGC to disable calls to System.gc(). Note that the JVM still performs garbage collection when necessary.

Should I call System.gc() in my java persistence project?

Generally System.gc() is not guarenteed to perform a garbage collection. Ultimately it is up to the JVM to decide. See the javadoc.

Have you observed what happens when you are approaching your memory limits of the JVM, does garbage collection happen then ? If not and you receive an OutOfMemoryError, you either are retaining something longer than you need to, or actually need extra heap allocated to your VM.

In anycase System.gc() I believe shouldn't be used to solve such problems.

Calling System.gc( ) explicitly?

The best way, in my opinion, to think of the System.gc() method is as a "hint" to the VM that garbage collection should run. That said, much like a large percentage of "optimizations" people think they are performing, it's usually best to just let the system take care of things on its own. Systems are evolving etc, etc, etc. There are still some instances where the developer may actually know better and the use case for it is probably very similar to why some code is still written in assembly (most of the time, the compiler is better, but in a few instances -- or with a few developers -- humans can actually write more efficient code).

One example I've seen used in the past to justify its existence is in the event that a large number of objects were allocated and you as the developer know the instant they are no longer going to be used. In that case, you may have more information about the memory utilization than the GC does (or at least, before it realizes it) and, since the amount of memory reclaimed will be significant, it makes sense to suggest that it runs.

Good practice to call System.gc()

It's fine to call System.gc(). Do use a memory analysis tool to check that it's helping in your case.

The spec can't guarantee any results since the vm might've just done a GC.

Why does System. gc () seem to have no effect on some JVMs

I think it is due to the fact that I
call System.GC() fairly regularly

You should not do that, it's almost never useful.

A garbage collector works most efficiently when it has lots of memory to play with, so it will tend to use a large part of what it can get. I think all you need to do is to set the max heap size to something like 32MB with an -Xmx32m command line parameter - the default depends on whether the JVM believes it's running on a "server class" system, in which case it assumes that you want the application to use as much memory as it can in order to give better throughput.

BTW, if you're running on a 64 bit JVM on the server, it will legitimately need more memory (usually about 30%) than on a 32bit JVM due to larger references.



Related Topics



Leave a reply



Submit