简体   繁体   中英

Java - Can objects which are executing methods be garbage-collected?

In Java, I've done things like the following without thinking much about it:

public class Main {

    public void run() {
        // ...
    }

    public static void main(String[] args) {
        new Main().run();
    }
}

However, recently I've become unsure as to whether doing that is safe. After all, there is no reference to the Main object after it's created (well, there is the this reference, but does that count?), so it looks like there's a danger that the garbage collector might delete the object while it's in the middle of executing something. So perhaps the main method should look like this:

    public static void main(String[] args) {
        Main m = new Main();
        m.run();
    }

Now, I'm pretty sure that the first version works and I've never had any problems with it, but I'd like to know if it's safe to do in all cases (not only in a specific JVM, but preferably according to what the language specification says about such cases).

If an object method is being executed, it means someone is in possession of that reference. So no, an object can't be GC'd while a method is being executed.

For the most part garbage collection is transparent. It's there to remove the unnecessary complication of manual memory management. So, it will appear not to be collected, but what actually happens is more subtle.

Trivially, a compiler may completely elide the construction of the object. (By compiler, I mean a lower level compiler than javac. The bytecodes will be a literal transliteration of the source.) More obscurely, garbage collection typically runs in separate threads and actually remove the unaccessed object as a method on it is being run.

How can this be observed? The usual suspect in a finaliser. It may run concurrently with a method running on the object. Typically you would get around this problem with synchronized blocks in both the finaliser and the normal methods, which introduces the necessary happens-before relationship.

m is just a variable which has reference stored. This will be used by programmer to use the same object further to write logic on same object.

While execution, program will be converted to OP-CODES / INSTRUCTIONS . These INSTRUCTION will have the reference to object(it is a memory location after all). In case m is present, location of object will be accessed via INDIRECT REFERENCE. If m is absent, the reference is DIRECT.

So here, object is being used by CPU registers, irrespective of use of reference variable.

This will be available till the flow of execution is in scope of main() function.

Further, as per GC process, GC only removes objects from memory, once GC is sure that the object will not be used any further.

Every object is given chance to survive a number of times(depends on situation and algorithm). Once the number of chances are over, then only object is garbage collected.

In simpler words, objects which were used recently, will be given chance to stay in memory. Old objects will be removed from memory.

So given your code:

public class Main {

public void run() {
    // ...
}

public static void main(String[] args) {
    new Main().run();
}
}

the object will not be garbage collected.

Also, for examples, try to look at anonymous class examples. Or examples from event handling in AWT / SWING.

There, you will find a lot of usage like this.

The accepted answer is not correct. Whether the object can be GCed or not depends on if your public void run() {// ...} method has a reference to the class instance (this). Try:

public class FinalizeThis {

    private String a = "a";

    protected void finalize() {
        System.out.println("finalized!");
    }

    void loop() {
        System.out.println("loop() called");
        for (int i = 0; i < 1_000_000_000; i++) {
            if (i % 1_000_000 == 0)
                System.gc();
        }
        // System.out.println(a);
        System.out.println("loop() returns");
    }

    public static void main(String[] args) {
        new FinalizeThis().loop();
    }
}

The above program always outputs

loop() called
finalized!
loop() returns

in Java 8. If you, however, uncomment System.out.println(a) , the output changes to

loop() called
a
loop() returns

There is no GC this time because the method called references the instance variable (this.a).

You can take look at this answer

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM