3

You can garbage collect in Java simply by calling System.gc() but sometimes this "stalls" the application. Is it a bad idea to garbage collect like this and avoid stalls:

new Thread(new Runnable() {
   public void run() { 
      System.gc(); 
   }
}).start();

Or might this lead to even more problems?

haylem
  • 22,460
  • 3
  • 67
  • 96
anon
  • 33
  • 2
  • 1
    That will only call System.gc() once ... and don't you think Java does its garbage collection in another thread already? – Marcelo May 31 '11 at 20:56
  • 4
    The question in the title can be answered with "Yes, the GC is smart. In fact, it's smarter than you are and it's autonomous." ;) Why do you think you have to call `System.gc()` in the first place? And do you understand what causes these stalls (not all GCs have them, by the way)? If so, a bit of thinking should answer your question. If not, you should brush up your understanding of GC in general and the ones of modern JVMs in particular before you try to outsmart them. –  May 31 '11 at 20:56
  • If what you want is really to tweak the GC to avoid stalls and not to free memory, you may also want to experiment with other GCs in the Oracle JVM (and consider using the server VM). That can help. Give more details on your use case if you can. – haylem May 31 '11 at 23:17

6 Answers6

15

First Things First: DO NOT CALL THE GC EXPLICITLY

Except if you have a very good reason for it. And even if you think you do, you probably don't.

The GC Knows What It's Doing (most of the time...)

If you kept reading, I'm assuming you have a really awesomely good (albeit probably twisted) reason to attempt to screw around with the GC, even though it is very likely to be a lot clever than you are at determining when it should collect memory. Also, keep in mind that by calling it explicitely you confuse it and screw up its heuristics, so it gets less clever than it was before. All because you attempted to outsmart it.

The GC Doesn't Always Care About What You Say

If you do this for a very good reason, or in a case where you really want to ensure that you start an intensive code section with the best memory state possible, you need to know this probably won't work: calls to System.gc() do not guarantee a garbage collection to take place, as mentioned by its Javadoc (emphasis mine):

Calling the gc method suggests that the Java Virtual Machine expend effort toward recycling unused objects.

Other Recommendations

Hunt Down and Kill (Bad) Explicit GC

  • turn on -XX:+DisableExplicitGC (if your JVM supports it) to prevent those crazy calls of doing any harm (credit to Fredrik in the comments)
  • look with your favorite IDE or grep for calls to System.gc() and its equivalents and get rid of them.

Find Another Way

See Grooveek's answer for other useful suggestions (like using WeakReferences).

Experiment with Other GCs and Fine-Tune Your VM for Your App

Depending on your use case, maybe experimenting with other GC implementations might help: CMC, G1, ParallelGC, etc... If you want to avoid "stalls", I have had very good results with G1 since its introduction in the latest Java SE 6 updates and since the Java 7 release, running intensive enterprise applications for long-running periods.

Just be aware that JVM tuning is a very complicated art.

Further Reading

You can flip through these for a lot more details:

* Use with care: sometimes not perfectly up-to-date, doesn't document everything, and lists a lot of experimental features, or HotSpot-only features.

Community
  • 1
  • 1
haylem
  • 22,460
  • 3
  • 67
  • 96
  • 2
    One would think that if you were to allcaps something you would spell-check. I guess not. – Stefan Kendall May 31 '11 at 20:56
  • 2
    @Stefan Kendall: One would think that language pedants would give time for answers to be edited by non-english natives. But thanks for pointing out my mistake, no matter how nicely :) – haylem May 31 '11 at 20:57
  • Maybe you should add "And when you're done, that. Make sure you also add -XX:+DisableExplicitGC to your JVM options". – Fredrik May 31 '11 at 20:59
  • 2
    @Marcelo Hernández Rishmawy : yeah I saw that one and thought "whoops"... Had even corrected it before your comment appeared :) In all fairness, Stefan's comment is completely valid as I should spell-check before hitting submit (and I'll even +1 him for it), but I often like to edit my answers in very short bursts so that I can improve it with small iterations. – haylem May 31 '11 at 21:08
  • (in the voice of the Month Python Holy Grail room guard) Umm but ahhh...umm but ahhh...what if we really wanted to call the garbage collector? ;) – riwalk May 31 '11 at 21:19
  • @Stargazer712: If you really must, via JVMTI: http://download.oracle.com/javase/6/docs/platform/jvmti/jvmti.html#ForceGarbageCollection . But you wouldn't, really :) (OK, maybe for or debugging or profiling) – haylem May 31 '11 at 22:50
3

Yes, most times it is a very bad idea to call System.gc(). There are exceptions but they are few and it is mostly better to spend the time making sure you are not doing things that hurt performance in a GC environment and to study and make sure you understand how a gc works than to try to handle it yourself by explicitly calling System.gc().

Fredrik
  • 5,759
  • 2
  • 26
  • 32
  • OK, thanks for answering my question instead of acting like I don't know anything. In my application, I set it to garbage collect right after it stops doing something that is very processor-intensive and might continue for a couple hours on end, but of course you know more about this than I do (that's why I'm asking this). Thank you for responding, I'll go read up some more. – anon May 31 '11 at 21:04
  • @anon There are a few really good blogs posts on this blog, I think they are linked: http://chaoticjava.com/posts/how-does-garbage-collection-work/ – Fredrik May 31 '11 at 21:26
2

I can't beat @haylem answer's clarity and force, sorry. But let me add that there are a lot of (better) ways to manage memory in Java. There is, for example, WeakReference and collections which handle these, like WeakHashMap. These are deterministic ways to handle memory, though explicit calls to GC are not, as per 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.
Grooveek
  • 10,046
  • 1
  • 27
  • 37
  • Actually, maybe you don't beat it, but it's a very nice complement and I should have mentioned WeakReferences. Very good point. – haylem May 31 '11 at 21:12
0

Apart from what was already said so far, the whole idea is horribly flawed because you sadly miss one important detail:

While a full GC is running the application will be stopped! (at least currently on a modern Hotspot VM - and what else would you be using?)

There's a concurrent mark & sweep implementation in hotspot (though afaik not activated by default), but that incurs some extra overhead and still has to stop all threads before doing the sweep. So basically unimportant from which thread you do System.gc() the VM will wait for all threads to reach a safe point, stop them and then do the collection. So using a thread is completely useless.

Voo
  • 29,040
  • 11
  • 82
  • 156
0

I totally agree that explicitely calling the garbage collector is not recommended in general. It can stall the application for several seconds and sometimes minutes. This is usually not an issue if you are dealing with a background service, but if it is exposed to users, they will have a bad experience.

However, there are extreme cases when you will want to do this: when memory is running really short and the application could crash. But a lot can be done is the application's design and implementation to avoid those situations.

One of the features of Java I love when it comes to recollecting memory and avoid memory leak are WeakReference objects. They are your friends.

Jérôme Verstrynge
  • 57,710
  • 92
  • 283
  • 453
  • "when memory is running really short and the application could crash" - if the application is running low on memory the JVM will try a garbage collection itself before failing so no, also no good reason. – Voo May 31 '11 at 21:19
0

As others have said, calling System.gc() is usually a mistake. (Not always ... )

Assuming that you have one of those rare use-cases where calling System.gc() is likely to be beneficial, there are two cases to consider:

  • If your JVM is using a classical "stop the world" collector, then running it in a separate thread will make no difference. The GC stops all application threads for the duration.

  • If your JVM is running a concurrent collector, then running it in a separate thread may be a good idea. It is true that all collectors have a phase in which all threads are stopped, but calling System.gc() is documented as returning after "the Java Virtual Machine has made a best effort to reclaim space from all discarded objects". So running it in a separate thread will allow the current thread to do something else. However, you need to be careful to avoid launching multiple threads that each call System.gc(); i.e. the code that is responsible for launching the thread needs to keep track of any previous GC threads.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216