ChatGPT解决这个技术问题 Extra ChatGPT

How many objects will be eligible for garbage collection after executing "m1=null; m2=null;"?

I am confused to understand after executing m1 = null; m2 = null;. How many objects will be eligible for garbage collection?

public class MyTest {
    MyTest m;

    void show() {
        System.out.println("Hello this is show method.");
    }

    public static void main(String args[]) {
        MyTest m1 = new MyTest();
        MyTest m2 = new MyTest();
        MyTest m3 = new MyTest();
        m1.m = m2;
        m2.m = m3;
        m3.m = m1;
        m1 = null;
        m2 = null;
        // Question here: How many objects will be eligible for garbage collection?
    }
}
m3 to garbage collector "Those are not the two instances you are looking for!"
@rakeb.mazharul: Interesting? The reachability aspect of the question is extremely straightforward, on the level of "three houses are connected by one-way streets in a loop. Which ones can I drive to from house A?" That kind of thing needs to be second nature if you're going to reason about the memory behavior of any nontrivial garbage-collected program. There's some complication due to optimization, but the accepted answer doesn't even mention that, and I doubt most of the voters noticed.
Every answer says either "three" or "zero". The question is not answerable because we do not know how many objects are in the args array. Do people think that array and its elements are not objects?
@EricLippert But none of the elements m1,m2 or m3 are in the args array. And all elements in the args array are reachable, so I don't see how the args array affect the number of objects elibible for GC.
@taemyr, they must be reachable from a living root. Why is args alive? The GC can know it is never used, and therefore can be dead.

C
Codebender

Zero.

Object reference diagram looks like this:

https://i.stack.imgur.com/gcJai.png

You can see that the reference is circular. A reference from main to m3 keeps the m3 object alive. In turn, m3 keeps alive m1, which keeps m2 from GC.

Note that if you set m3 to null, all three objects would become eligible for GC at once, despite circular references existing for each one of them. GC is smart enough to figure out that all references are coming from GC-eligible objects, and collect all three.


How did you draw this that fast? +1
Technically GC is not smart enough to figure out circular references, but it works by marking accessible objects from GC roots, hence avoiding the circular reference problem...
@Codebender Avoiding the problem is smart enough ;-)
@Codebender Actually it must figure out circular references to some extent, since it traverses (potentially) the entire object graph, and its algorithm doesn't fall apart when it hits cycles.
m
mazhar islam

Potentially all 3 of them. No variables are referenced after the // marker, so the optimizer is within its rights to drop them off the frame at this point.


I think the OP's concern is somewhere else! But you are right anyway! +1
I'm reminded of Raymond Chen's excellent article, blogs.msdn.com/b/oldnewthing/archive/2010/08/10/10048149.aspx . However, I am unsure if the Java GC has similar rules. It's possible that the Java specification has a documented promise not to collect objects with rooted reference.
@Brian: Java is as smart as C# in that regard. It must be emphasized that the last actual access to the instance data of an object isn’t necessarily the last access in program order, as the optimizer may generate code holding the actual field values in registers, not needing the object even while working on its data. In the question’s example, none of the assignments has a real effect, so all objects might get collected right after creation or never get created in the first place. See also finalize() called on strongly reachable object in Java 8
P
Peter Mortensen

Voila! GC will collect nothing here! Let's see what actually is going on here. When you created three objects of m1, m2 and m3 of MyTest, the object was created like below (say the object reference id starts from 410):

m1    MyTest  (id=410)
    m    null
m2    MyTest  (id=412)
    m    null
m3    MyTest  (id=414)
    m    null

When you initialize

m1.m = m2;
m2.m = m3;
m3.m = m1;

The objects are now looks like:

m1    MyTest  (id=410)
    m    MyTest  (id=412)
m2    MyTest  (id=412)
    m    MyTest  (id=414)
m3    MyTest  (id=414)
    m    MyTest  (id=410)
        m    MyTest  (id=412)
            m    MyTest  (id=414)
                m    MyTest  (id=410)
                    .
                    .
                    . (This is circular)

But after you reinitialized m1 and m2 to null, the objects look like:

m1    null
m2    null
m3    MyTest  (id=414)
    m    MyTest  (id=410)
        m    MyTest  (id=412)
            m    MyTest  (id=414)
                m    MyTest  (id=410)
                .
                .
                .

Look, m1 and m2 are null now, but their references are still alive in m3!


A
Aron_dc

None as they are still all reachable through the circular reference you build there through m3


关注公众号,不定期副业成功案例分享
Follow WeChat

Success story sharing

Want to stay one step ahead of the latest teleworks?

Subscribe Now