1
public class Main {

    public static void main(String[] args) throws InterruptedException {
        ClassA a = new ClassA();
        a = null;

        //Runtime.getRuntime().gc();
        Thread.sleep(4000);
    }
}

public class ClassA {

    @Override
    public void finalize(){
        System.out.println("cleaned");
    }  
}

With the above code finalize() never executes. Nothing is printed to the console. When Removing comment from gc(), finalize() executes, and "cleaned" is printed to the console. Why do I have to call to the garbage collector explicitly ?

bestsss
  • 11,796
  • 3
  • 53
  • 63
Yaron Levi
  • 12,535
  • 16
  • 69
  • 118
  • 1
    Calling the garbage collector explicitly doesn't guarantee anything either. You were just lucky that it worked. – Sergei Tachenov Feb 26 '11 at 09:54
  • @Sergey Tachenov, virtually any JVM honors it (it can be disabled by a command line parameter, though). Yet, even Sun uses explicit calls to System.gc(). Found post about: http://stackoverflow.com/questions/4784987/calling-system-gc-explicitly/4796276#4796276 – bestsss Feb 26 '11 at 09:56
  • The JVM only garbage collects objects when it needs to. This minimizes the work the JVM does and improves performance. – Peter Lawrey Feb 26 '11 at 09:56
  • @bestsss, actually it's perfectly fine when Sun does it, because they know what exactly System.gc() does in their particular implementation. If you mean that virtually any JVM honors the requirement to actually garbage collect as much as reasonably possible when you run System.gc(), you're right. However, the definition of "reasonably possible" could depend on a particular implementation. In this particular example, some implementations may choose not to garbage collect that class instance because it's too small or because there is much free memory already. – Sergei Tachenov Feb 26 '11 at 10:33
  • @Sergey, you say "lucky"; which implies that something supernatural needs to happen while it's actually the norm to perform a full garbage collection to honor the call. Note: finalization is still different than the GC, it's executed entirely separately. – bestsss Feb 26 '11 at 11:20
  • @bestsss, by "full", do you mean that every single object is guaranteed to be garbage-collected if the garbage collector is invoked explicitly? By "lucky" I meant that some implementations may choose to leave some objects for the next collection run, which may never happen if the application exits soon enough. I can be wrong, though, as my knowledge is very lacking in this area. – Sergei Tachenov Feb 26 '11 at 11:28
  • @Sergey, *by "full", do you mean that every single object is guaranteed to be garbage-collected if the garbage collector is invoked explicitly*, practically yes. "Full" usually refers to the check of the tenured, old-gen objects that are checked very, very rarely (when need to resize heap for instance). – bestsss Feb 26 '11 at 11:37
  • @bestsss, then I got confused by the docs. They say "When control returns from the method call, the virtual machine has made its best effort to recycle all discarded objects." - I wonder why, instead of this "best effort", they didn't simply write "This method forces the VM to recycle all discarded objects." As it is, it sounds like there is no strong guarantee. [Various sources](http://thestudentdaily.com/2010/11/core-java-interview-questions-and-answers-for-freshers/607/) also suggest this. – Sergei Tachenov Feb 26 '11 at 11:48
  • @Sergey, the docs are correct. There is no strong enforcement, I said "the norm" not always. The spec does gramy freedom to treat the call as no-op, of course. For example if you read the doc of Object.wait(), it can be treated as no-op (sporadic wake-up) as well. Point is: thet spec doesn't try to enforce absolute rules to ease the implementers. – bestsss Feb 26 '11 at 11:51
  • @bestsss, I see, looks like I just misused the word "lucky". Then what about finalization? You have mentioned that it's different and executed separately, but it obviously should be executed before the memory occupied by an object is returned to the heap. Does that imply that it is also the norm that finalization takes place during the call to System.gc()? – Sergei Tachenov Feb 26 '11 at 11:56
  • @Sergey, you have misunderstood how finalization works. During the gc process the objects which classes have defined 'finalize' are scheduled for finalization. There is a separate thread that executes the finalizers. During the finalization an object can be "resurrected" and effectively not garbage collected. So no: the finalization does not occur during System.gc but the objects are scheduled for. – bestsss Feb 26 '11 at 14:36
  • ...there is one more method `System.runFinalization()` that is supposed to "run" the finalization or at least 'wait' for the finalization queue getting empty. It's hard to explain the entire process in a few messages and we did awfully derail the topic. – bestsss Feb 26 '11 at 14:39

1 Answers1

16

Finalization is not guaranteed to be executed with the virtual machine exit. There is no explicit GC for and the finalization is run in a dedicated thread which also exits. Link to explanation: http://download.oracle.com/javase/6/docs/api/java/lang/System.html#runFinalizersOnExit%28boolean%29

If you need clean up code use:
Runtime.addShutdownHook http://download.oracle.com/javase/6/docs/api/java/lang/Runtime.html#addShutdownHook%28java.lang.Thread%29

bestsss
  • 11,796
  • 3
  • 53
  • 63