I've found a lot of questions on Stack Overflow that go something like this:
My Java program keeps crashing because it's running out of memory, but I'm calling
System.gc()to do manual garbage collection. What's wrong?
Java's automatic garbage collection is a wonderful thing and it's enabled developers to focus on writing code instead of tracking down bugs, but I feel like we now have a generation of programmers who don't understand the subtle details of memory management. If you do Java development (or any kind of managed memory language development), you should at least take some time to understand the rules of garbage collection.
Garbage collection implementation is largely dependent on your JVM, but the rules of when objects are eligible for collection are the same. Here's Oracle's documentation on this:
An object is eligible for garbage collection when there are no more references to that object. References that are held in a variable are usually dropped when the variable goes out of scope. Or, you can explicitly drop an object reference by setting the variable to the special value null. Remember that a program can have multiple references to the same object; all references to an object must be dropped before the object is eligible for garbage collection.
The only thing I'd like to add to that is to point out that the object becomes eligible for garbage collection. It does not actually get collected. Your JVM is going to figure out the best time to actually do the garbage collection.
That brings us back to
System.gc(). The Javadocs for this method say that it "runs the garbage collector". That's a little misleading. If you read the details, we learn that it only suggests to the JVM that it should do garbage collection. Furthermore, even if the suggestion is taken, the garbage collection will probably happen asynchronously, so you might not have more memory available instantly.
If you find
System.gc() in your code, that's probably something you want to flag for review. It's not necessarily bad, but it shows that there's a problem there that's being solved in a way that may or may not be stable. It might work today, but it could fail the next time it's run. Here's a few alternatives:
- Re-read those rules of garbage collection eligibility. You might be holding on to references to objects without realizing it.
- Adjust your JVM memory arguments and run profiling tools to figure out what's going on and why you seem to be running out of memory.
Let's all recognize that
System.gc() isn't an absolute solution and you can't rely on it as a fix and it's probably a sign that you have some less-than-good code on your hands.
Alright, well I've managed to write this whole thing without making any kind of joke about garbage collection and code smell, so I think I should just stop now.