3

I am reading Thinking in Java, 4th Edition. I found a problem: when I tested the source code in Eclipse IDE, I found the results are different. I hope someone can help me!

Here is the source code

class Book {
    boolean checkedOut = false;

    Book(boolean checkOut) {
        checkedOut = checkOut;
    }

    void checkIn() {
        checkedOut = false;
    }

    protected void finalize() {
        if(checkedOut)
            System.out.println("Error:checked out");  
            //Normally,you'll also do this:
            //super.finalize();//Call the base-class version
    }
}


public class TerminationCondition {
    public static void main(String[]args) {
        Book novel=new Book(true);

        //Proper cleanup:
        novel.checkIn();

        //Drop the reference,forget to clean up:
        new Book(true);
        new Book(true);
        new Book(true);

        //Force garbage collection & finalization:
        System.gc();
    }
}

The result of the Book:

Error: Checked out

The result of IDE

(nothing)

The version of Java I use:

Java version "1.7.0_51"
Java(TM) SE Runtime Environment (build 1.7.0_51-b13)
Java HotSpot(TM) 64-Bit Server VM (build 24.51-b03, mixed mode)

The version of Java in the Book is Java 5. Did something about finalize method change?

Michael0x2a
  • 58,192
  • 30
  • 175
  • 224
Wenchao Cai
  • 83
  • 1
  • 4
  • 4
    There's no gurentee that 1: `System.gc` will cause a garbage collection, 2: `finalize` will ever be called. It's possible the termination of the JVM has prevented the `gc` from processing the release of the object in its normal fashion ... or some such... – MadProgrammer Sep 14 '14 at 06:15

3 Answers3

1

JVM has its own garbage collection management policy,even if you call finalize() separately OR not! The JVM does so optimally that the user don't need to intervene in the process of garbage memory cleanup.

So,what you're observing has nothing to do with Java version OR anything! It just totally depends on JVM and it's automatic memory management policy.

Am_I_Helpful
  • 18,735
  • 7
  • 49
  • 73
0

Your main thread is exiting before GC is run . So you are not getting any output. Do the below changes in your main method and you will see the output:-

System.gc();
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
Manjunath
  • 1,685
  • 9
  • 9
0

The version of Java in the Book is Java 5. Did something about finalize method change?

If you read the specifications for System.gc() and related things, you will see that there few if any guarantees of what is going to happen:

  1. It is not guaranteed that calling System.gc() will cause anything at all to happen. Seriously.

  2. It is not guaranteed that all garbage will be collected.

  3. It is not guaranteed that garbage objects will be finalized ... not withstanding the finalize() method.

The real problem here is that example you are looking at is making unwarranted assumptions. It happened to work in older versions of Java. It doesn't work with more recent ones ... or something like that. It is just a bad example.

But this does (I hope) demonstrate to you that it is unwise to rely on finalize methods being called at a predictable time. In fact, it is best not to use finalize for anything ... except for "belt and braces" tidy up code.


In fact, finalization typically happens after the garbage collector has finished. (It is done by a daemon "finalization thread" that works through all of the objects that have been identified as unreachable, and requiring finalization.) So what is probably happening in your example is that the JVM is exiting after the GG has run, but before the finalization thread gets a chance to process the finalizable objects.

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