Smart Garbage Collection?

爱⌒轻易说出口 提交于 2019-12-01 21:09:48

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().

haylem

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.

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.

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.

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.

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!