Interview question: Objects eligible for garbage collection

前端 未结 7 864
无人共我
无人共我 2020-12-02 19:03

Give the following code:

class A {
    Boolean b;
    A easyMethod(A a){
        a = null;
        return a;
    }
    public static void main(String [] args         


        
相关标签:
7条回答
  • 2020-12-02 19:39

    The question is how many objects are eligible for garbage collection right before // Some other code.

    The question is nonsensical.

    Garbage collectors act at run-time on the information available there. Reachability is determined by the global roots stored in registers, on the thread stacks and in global variables. The contents of registers and the stacks are the culmination of many stages of compilation that completely mangle the code. The concepts of lexical scope and line numbers from the source code no longer exist so it is nonsensical to ask questions about what the GC might see at certain points in the source code because those points do not exist in the world of the GC.

    So we must first assume a direct correspondence between the source code and the generated code or we cannot even make sense of the point in the code that the question refers to. I cannot think of any working VM that actually does this in practice and, in fact, Java probably has high-level language constructs that cannot even be compiled to bytecode in this way.

    Next, we must assume a model for the way local references are kept on the stack. Rather than assuming some ill-defined model in order to derive a random answer I'm going to show that the choice of model allows us to arrive at answers ranging from "nothing is eligible for GC" to "everything is eligible for GC". This full range of justifiable answers really highlights just how bad that question is.

    Consider a simple model where intermediate values (the results of all subexpressions as well as variables) are pushed onto the stack until the end of the function. Simple compilers and virtual machines like HLVM and .NET on Windows Phone 7 actually work like this in practice even though this retains references for longer than necessary. With this model, each new A() pushes a reference onto the stack until the function returns so all three are reachable from the stack at the point in question and, therefore, nothing is eligible for garbage collection.

    Consider a model where references are removed from the stack at the first point where they are never read from again. This is closer to how production virtual machines like .NET and OCaml work except they keep local references in registers when possible and spill to pre-allocated entries in the function call's stack frame otherwise, overwriting dead locals to minimize the size of the stack frame. With this model, all references are dead at the point in question so none are reachable and, therefore, all three of the newly allocated objects are eligible for garbage collection as well as the args array and all of the strings it references.

    So we have not only shown that answers ranging from nothing to everything can be justified but we have even cited real working virtual machines and garbage collectors that implement these models so our predictions are testable.

    If I were given that question in an interview I would test the interviewer by explaining some of this. If they reacted well by expressing an interest in learning then I would still be interested in the job. If they reacted badly by trying to defend their ill-defined assumptions and untestable predictions then I would not want to work with them.

    0 讨论(0)
  • 2020-12-02 19:40

    Assuming go is supposed to be easyMethod it works like this

    class A {
        Boolean b;
        A easyMethod(A a){
            a = null; // the reference to a2 was passed in, but is set to null
                      // a2 is not set to null - this copy of a reference is!
            return a; // null is returned
        }
        public static void main(String [] args){
            A a1 = new A(); // 1 obj
            A a2 = new A(); // 2 obj
            A a3 = new A(); // 3 obj
            a3 = a1.go(a2); // a3 set to null and flagged for GC - see above for why
            a1 = null; // so far, a1 and a3 have been set to null and flagged
            // Some other code 
        }
    }
    

    Two objects are eligible for garbage collection (a1 and a3). b is not because it's only a reference to null. No Boolean was ever made.

    To get around the inane subtleties of what // Some other code might be, I instead posit the question be reworded into the following:

    Prdict and explain the following output:

    class A {
        int i;
        A(int i) { this.i = i; }
        public String toString() { return ""+i; }
        A go(A a){
            a = null; // the reference to a2 was passed in, but is set to null
                      // a2 is not set to null - this copy of a reference is!
            return a; // null is returned
        }
        public static void main(String [] args){
            A a1 = new A(1); // 1 obj
            A a2 = new A(2); // 2 obj
            A a3 = new A(3); // 3 obj
            a3 = a1.go(a2); // a3 set to null and flagged for GC - see above for why
            a1 = null; // so far, a1 and a3 have been set to null and flagged
    
            test(a1);
            test(a2);
            test(a3);
    
        }
        static void test(A a) {
            try { System.out.println(a); } 
            catch(Exception e) { System.out.println((String)null); }
        }
    }
    

    And output:

    c:\files\j>javac A.java
    
    c:\files\j>java A
    null
    2
    null
    

    And the followup is that at that point, a1 and a3 were eligible for GC, and a2 was not.

    The lesson from this question is that "Passing an object reference to a method and setting that reference to null does not cause the original reference to be nulled". That's the piece of knowledge the interviewer was attempting to test.

    0 讨论(0)
  • 2020-12-02 19:42

    First of all the interviewer is wrong about the Boolean -- there is no such object created by this code so there's nothing to be garbage collected.

    It is incorrect to speak of variables like b and a2 as being garbage collected. Objects are garbage-collected, not variables. If an in-scope variable references an object, then it cannot be garbage-collected. Simplistically, it's only when an an object is no longer referenced by any variable that it can be garbage collected.

    So we have three instances of A being created in this code. They start out referenced by a1 etc. but since variable references change I'll refer to the object instances as A1, A2, and A3. Since you haven't shown a definition of the go method I'm going to assume it's meant to be a call to easyMethod.

    Since the variable a1 is reassigned to null, nothing is pointing to instance A1, so it can be garbage-collected.

    Since the variable a2 is never reassigned (the assignment in easyMethod does not affect the original variable), instance A2 cannot be garbage-collected.

    Since easyMethod always returns null and a3 is assigned the result of that method, nothing is pointing to instance A3, so it can also be garbage-collected.

    0 讨论(0)
  • 2020-12-02 19:48

    Your question is quite confused.

    The garbage collector works on objects, not on variables. So when you say that a2 is eligible for GC it mean nothing. You should say the object referenced by a2 at line N is eligible for GC at the line N+M.

    In your example you only have 3 objects being instantiated. It is the first create A and the last create A instance that are eligible for GC.

    0 讨论(0)
  • 2020-12-02 19:51

    For a2's original referant it actually completely depends on what happens in "some other code". If "some other code" doesn't use a2 or a3, then the original a2 object is eligible for garbage collection.

    That's because the runtime doesn't have to care about lexical scope. It just needs to know that an object can never be referenced again. Therefore, if "some other code" doesn't utilize a2 or a3, the object they point to can never be referenced again and so is already available for garbage collection.

    0 讨论(0)
  • 2020-12-02 19:54

    Can you please me explain me why a2 and a3 aren't being garbage collected ?

    Because a2 and a3 are not objects. They are variables. Variables are not collectable for the simple reason that they are not allocatable.

    0 讨论(0)
提交回复
热议问题