Overview

Invoking System.gc() can have serious impact

5 Comments

Not taking JavaDoc seriously can easily happen to any developer. Or maybe you haven’t read that specific part of it, you should better have read. If you did and cannot see a problem locally, you might be tempted to ignore it.

Here is an often ignored part from java.text.SimpleDateFormat JavaDoc:

 * Date formats are not synchronized.
 * It is recommended to create separate format instances for each thread.
 * If multiple threads access a format concurrently, it must be synchronized
 * externally.

Perhaps that warning isn’t strong enough, because it reads: “It is recommended”.
This leads to this highly dangerous line of code I have seen in almost every project and is likely to produce hangs in concurrently accessed code.

private static final SimpleDataFormat DATE_FORMAT = new SimpleDateFormat("yyyy.MM.dd");

But it gets worse with System.gc().
There is no warning in the JavaDoc:

* Calling the gc method suggests that the Java Virtual
* Machine expend effort toward recycling unused objects in order to
* make the memory they currently occupy available for quick reuse.
* When control returns from the method call, the Java Virtual
* Machine has made a best effort to reclaim space from all discarded
* objects.

Doesn’t sound too bad, does it? You should wonder what “suggests” and “best effert” really means. Perhaps you are tempted to use System.gc(), so you might look on the internet for other people using this, hoping for an explanation what in reality happens. You might find good insights on Stackoverflow. But what exactly this does nobody seems to know.

I think a picture tells more than thousand words:

We are looking at a pretty big system of one of our customers. It has 14GB of heap and we helped them to bring down the memory consumtion so that the app ran quite well. However there were still pretty long pause times (so called stop the world time). The graph was created from a Garbage Collection log and points us to the cause of the pause times. The blue line shows Garbage Collection activity. So why are there exactly 13 spikes with up to 35 seconds? All the other activity seems to be really fast.
The reason for those 13 spikes is simple: They all were caused by an invocation of System.gc().

So what happens? Calling System.gc() seems to effectively stop any optimization the GC is doing, forcing a full collection to start, rather than the optimized CMS Algorithm used.

Note: This system is using a Sun 1.6.0.18 64 bit HotSpot Server VM. GC is set to -XX:+UseConcMarkSweepGC and -XX:+UseParNewGC. System.gc() does not have to produce results like that. Your results might vary. However also others have reported, that when using CMS and System.gc() a Full GC is always performed.

If you cannot find yourself invoking System.gc(), they might hide deeply in a used library. To fix this, you can use the the server argument “-XX:+DisableExplicitGC”. This argument is also recommended by the SUN/Oracle performance tuning guide.

Tags

Kommentare

  • kk

    This is one of the reasons why mongodb was not chosen as data store for one of our projects. Using RAII in Java by using finalizers and calling System.gc() is not just wrong but dangerous!

    http://github.com/mongodb/mongo-java-driver/blob/master/src/main/com/mongodb/util/SimplePool.java

  • Amrr

    Hi there, great article, but …

    I’ve been dealing for the past 2 months with a tomcat instance which is having GC issues.

    The issue is that tenured Gen never gets collected, and the only way I can remediate this is to hit ‘Force Garbage Collection’ (this is a page on a manager-like servlet called Psi Probe).

    If I don’t do this, RAM usage keeps going up gradually over a period of days, until the server starts becoming unresponsive. It never seems to hit OutOfMemoryError.

    I’ve tried messing with ConcMarkSweep, and other options, with disastrous consequences (with CMS, the free ram goes up, but the total ram usage never clears down, even after hitting ‘Force GC’. So, when tomcat freezes, it freezes more ‘suddenly’).

    Code-wise, I’ve managed to reduce the issues by removing some usage of ThreadLocals in one servlet. So, I’m pretty sure I know which servlet is causing the problem, and that it relates to some heavy AES encryption and IO tasks that it’s performing. It’s proving very hard to replicate the issue on UAT, and really I need to understand the problem from a GC perspective.

    I can’t see any viable alternative at this point, other than scheduling a gc. I know System.gc() is wrong but I can’t afford another outage.

    Any advice?

    Sorry, that was a long ramble!

  • Amrr

    OK thanks Fabian, interesting answer.
    I can’t really provide all details. If I get to the bottom of the problem, I’ll let you know.

    Ta

  • Olli Plough

    5. August 2010 von Olli Plough

    You might try using Sun’s GC based on the train algorithm (http://java.sun.com/developer/technicalArticles/Networking/HotSpot/). It is an algorithm that is supposed to be able to cope well with that kind of situation you have.

    /Oliver

  • Friend

    11. August 2010 von Friend

    Sorry for my ignorance here, from the code snippet that you pasted above, which is

    private static final SimpleDataFormat DATE_FORMAT = new SimpleDateFormat("yyyy.MM.dd");

    For a “final static” variable what problem might we be running into if we were to use above code as is in any program.

Comment

Your email address will not be published. Required fields are marked *