38

Java automatically calls garbage collector, then why we need manual calls for garbage collection? When should use System.gc()

Nageswaran
  • 7,481
  • 14
  • 55
  • 74

7 Answers7

47

Java automatically calls garbage collector, then why we need manual calls for garbage collection?

We don't need them. Indeed, in most circumstances calling System.gc() is harmful for application performance. See my answer to "Why is it a bad practice to call system gc" for a detailed explanation.

When should use System.gc()

If the application knows it is going into a phase where it has nothing else to do AND the user is unlikely to notice a garbage collection, then maybe it is OK call to System.gc() in an effort to stop the user experiencing GC pauses in the future.

The downsides include:

  • Calling System.gc() typically triggers a full GC which takes significantly longer than a GC of the 'new space'.
  • The user may actually care / notice. For example, if you call System.gc() between "levels" in a game, you make loading the next level take longer.
  • By forcing the GC, you are causing the JVM to use extra CPU cycles, etc which may potentially interfere with other things that the user is doing on his machine.

(There can also be legitimate reasons to call System.gc() in unit tests, and during system debugging.)

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

There isn't a need to call for garbage collection explicitly and calling System.gc() is only a suggestion, the JVM can ignore your suggestion.

The only practical uses I can think of is

  1. During debugging, forcing a collection can expose a memory leak
  2. If the program goes through predictable cycles of intense computation followed by no computation (like a turn based game), during the no-computation period the CPU could be utilized for a suggested garbage collection to prevent jitter during the intense computation portions.
Tim Bender
  • 20,112
  • 2
  • 49
  • 58
  • 1
    @TimBender - actually, I don't see how running the GC could possibly "expose" a memory leak. Could you explain that? – Stephen C Jan 16 '12 at 12:40
  • 2
    When watching the heap of an application, one generally expects a saw tooth look in which the used heap size returns to roughly the same size after each GC. Applications that retain to much data (sort of a memory leak) tend to continue to grow the heap. – Tim Bender Jan 17 '12 at 01:51
  • I see what you are getting at. But you can achieve the same effect using a memory profiler ... without hacking your application to call the GC. – Stephen C Feb 21 '14 at 10:10
  • @StephenC Yes, I agree. I meant through a debugger, not in the application code and I see that is somewhat tangential to calling System.gc() explicitly. – Tim Bender Feb 21 '14 at 17:45
4

System.gc() is only a suggestion. But it does make sense in some situations.

Suppose you have class MyClass, and you're wondering how much memory does one instance take. What you can do is this (roughly speaking):

MyClass [] objects= new MyClass[100000];
System.gc();
long memoryNow = Runtime.getRuntime().freeMemory();
for (int i = 0; i < 100000; i ++) {
  objects[i] = new MyClass();
}
System.gc();
long memoryLater = Runtime.getRuntime().freeMemory();
int objectSize = (int)((memoryLater - memoryNow) / 100000);

There are other similar cases I've found System.gc() to be useful.

iluxa
  • 6,941
  • 18
  • 36
1

The garbage collector is always called by the JVM when there is not enough memory to allocate new objects into the heap. While calling the garbage collector, it follows the Stop the World norms and for this it calls the System.gc() method.

Also remember that the JVM also runs parallel gc threads to remove unused objects from memory . So everything and every minute JVM maintains heap memory and always tries to not overload it. So there is no any requirement to explicitly call System.gc() or Runtime.gc() method.

If you want more detail about this you can get here for the relevant information.

hexacyanide
  • 88,222
  • 31
  • 159
  • 162
Ishant
  • 11
  • 1
1

One aspect not yet mentioned is that some types of objects may ask entities outside themselves to do things on their behalf (e.g. give them exclusive access to a non-fungible resource like a file), to the detriment of other entities. When a garbage-collection is performed, the system will not only free up memory that was formerly occupied by unreachable objects, but it will also call finalize on objects that it notices have been abandoned, thus allowing such objects to notify outside entities that their services are no longer required. It is entirely possible for a program to reach a state where there's plenty of memory, but a necessary resource is unavailable because an object has been granted exclusive access and has since been abandoned without releasing it. Forcing the garbage-collector to run in such a situation may sometimes free up the necessary resource.

supercat
  • 77,689
  • 9
  • 166
  • 211
  • That is true. However, the fact that you *need* to do this means that the application is doing a bad job of managing the resources. A well-written application will use `finally` blocks (or similar) to ensure that resources don't "leak". – Stephen C Feb 21 '14 at 10:04
  • @StephenC: While it's true that well-written applications should deterministically clean up resources, ensuring that things would get cleaned up in case of exceptions was awkward until Java 7. Even in Java 7, some cases are still excessively difficult to handle cleanly (especially in cases where constructors throw exceptions). – supercat Feb 21 '14 at 16:45
  • Can you explain the problem with constructors in Java 7? Are you talking about bugs in the constructors themselves, or something else. – Stephen C Feb 21 '14 at 23:00
  • @StephenC: There are at least two problematic cases with constructors: (1) if the construction of a derived-class object requires acquiring a resource and passing it to the base-class constructor, it's difficult to avoid leaking that resource if the base constructor throws, since Java won't allow the base-constructor call to be wrapped in a `try/finally` block [even though the JVM would]; (2) if the base-class constructor acquires a resource and a derived-class constructor throws, the resource will leak unless the throw occurred within a try/finally block. Note that... – supercat Feb 21 '14 at 23:13
  • ...a field declaration like `myThing = new Thing();` cannot be wrapped in a try-finally, so if any such declaration throws, *whether or not it acquires resources*, base-class resource leaks will be hard to avoid since no reference to the base-class object will exist. The only way I know to avoid resource leaks in such cases is by using `ThreadLocal` to keep track of resources which have been acquired but not yet been "handed off" to entities that have promised to close them. – supercat Feb 21 '14 at 23:16
  • Re 1) A way to avoid the problem is to hide the subclass constructor, and expose a factory method instead. Then have the factory method pass the resource to the subclass constructor as an extra parameter. The factory method can then close the resource if the constructor does not terminate normally. Re 2) I think that the same approach works. The point is that the problem *can* be dealt with at source. – Stephen C Feb 21 '14 at 23:29
  • @StephenC: Using a factory method to attack problem #1 works, but is only usable if there's no need to construct subclass instances that use the resource. For the factory to perform the needed cleanup in scenario #2, it must somehow get a copy of the object under construction. One could, e.g. have the factory pass an `AutoCloseable[1]` array to the constructor, and have the base constructor store `this` there, but that entails an overly-close coupling between the base and derived classes, and there's no standard convention for it. – supercat Feb 21 '14 at 23:49
  • *"but is only usable if there's no need to construct subclass instances that use the resource."* I don't understand your point. Any place you write `new Subclass(...)` you can replace it with a call to a factory method. – Stephen C Feb 22 '14 at 00:16
  • I was wrong about case #2. The solution there is for the subclass constructor to wrap the code where it throws the exception in a try/finally ... and call the `close()` method on the superclass on the way out. – Stephen C Feb 22 '14 at 00:19
  • @StephenC: That works, provided that the exception is thrown in a place which *can* be wrapped with try/finally. If the exception is thrown from something like a field declaration `Thing thingie = new Thing(this, that, theOther);` there's no way to wrap that in a try/finally. – supercat Feb 22 '14 at 16:47
0

There is no need to call System.gc() or Runtime.getRuntime().gc(). The JVM internally controls garbage collection if it finds that it is running out of memory.

hexacyanide
  • 88,222
  • 31
  • 159
  • 162
Ritesh Kaushik
  • 715
  • 2
  • 13
  • 24
0

Garbage collection process is not under the user's control.So it makes no sense to call System.gc(); explicitly. It entirely depends on the JVM.

Few days back, I had asked exactly the same question : [Here].

In fact, many questions related to calling System.gc(); explicitly have been already asked and answered here. Calling System.gc(); explicitly is always considered as poor programming skill, although it won't do any harm.

Here are the few links that I you should go through it. It will definitely clarify your doubt.

PS : Btw, you should seriously take the extra effort to go through similar StackOverflow questions before posting about your doubts.

Community
  • 1
  • 1
Saurabh Gokhale
  • 53,625
  • 36
  • 139
  • 164
  • *"... although it won't do any harm"* - It will typically make your application go slower, and that counts as "harm". – Stephen C Nov 20 '17 at 04:28