有多少对象符合垃圾收集条件?

时间:2012-12-25 10:23:54

标签: java garbage-collection

1.  public class Tahiti {
2.      Tahiti t;
3.      public static void main(String[] args) {
4.          Tahiti t = new Tahiti();
5.          Tahiti t2 = t.go(t);
6.          t2 = null;
7.          // more code here
8.      }
9.      Tahiti go(Tahiti t) {
10.         Tahiti t1 = new Tahiti(); Tahiti t2 = new Tahiti();
11.         t1.t = t2; t2.t = t1; t.t = t2;
12.         return t1;
13.     }
14. }

当到达第7行时,有多少对象符合垃圾回收的条件?

根据此问题的答案,第11行没有符合GC要求的对象; 但据我说,至少有一个对象,t2,在第6行设置为null,应该有资格进行垃圾收集。

5 个答案:

答案 0 :(得分:7)

第6行的变量t2不是对象的唯一引用。从t到对象t2的引用是在函数go中创建的,而对象t2又保持对t1的引用,t1是函数go返回的相同对象。因此第6行只是减少了引用的数量,但仍然存在对象的实时引用。

编辑: 让我们尝试更详细的解释,首先我重新编写代码以使解释更容易。每行一个语句和较少混淆的变量名称+我用字母A,B和C标识了三个相关对象。

1.  public class Tahiti {
2.      Tahiti u;
3.      public static void main(String[] args) {
4.          Tahiti t = new Tahiti(); // object A
5.          Tahiti t2 = t.go(t);
6.          t2 = null;
7.          // more code here
8.      }
9.      Tahiti go(Tahiti s) {
10.         Tahiti s1 = new Tahiti(); // object B
11.         Tahiti s2 = new Tahiti(); // object C
12.         s1.u = s2;
13.         s2.u = s1;
14.         s.u = s2;
15.         return s1;
16.     }
17. }

在第4行:变量t被初始化以引用新对象。让我们将该对象称为A(它通常在java中没有名称,但为了这个解释,它会更容易)。

在第5行:t传递给函数go,所以我们转到第9行

在第9行:参数s引用在第4行创建的对象A

第10行:将变量s1初始化为指向对象B

第11行:初始化变量s2以引用对象C

第12行:s1.u设置为引用s2,这意味着对象B获得对C

的引用

第13行:s2.u设置为引用s1,因此对象C得到对B的引用

第14行:s.u设置为引用s2,这意味着对象A得到对C的引用,注意C也引用了B,所以此时有一个从A到B的链

第15行返回对象B并返回第5行

第5行:t2设置为参考对象B(B现在直接被t2引用两次,一次因为t指的是引用C的引用B的对象A)

第6行:参考t2设置为空,因此B丢失一个参考但是t仍然是活的,指向A指的是C指的是B

答案 1 :(得分:3)

您可以绘制一个表格,该表格在行之间进行映射,并且在行之后立即指向每个对象的访问路径列表,如下所示:

╔════════════╦═══════════════════════╦════════════════╦═══════════════════╗
║ After Line ║ Pointers to o1        ║ Pointers to o2 ║ Pointers to o3    ║
╠════════════╬═══════════════════════╬════════════════╬═══════════════════╣
║          3 ║ not allocated         ║ not allocated  ║ not allocated     ║
║          4 ║ main:t                ║ not allocated  ║ not allocated     ║
║          9 ║ main:t, go:this, go:t ║ not allocated  ║ not allocated     ║
║         10 ║ main:t, go:this, go:t ║ go:t1          ║ go:t2             ║
║         11 ║ main:t, go:this, go:t ║ go:t1, o3.t    ║ go:t2, o2.t, o1.t ║
║          5 ║ main:t                ║ main:t2, o3.t  ║ o2.t, o1.t        ║
║          6 ║ main:t                ║ o3.t           ║ o2.t, o1.t        ║
╚════════════╩═══════════════════════╩════════════════╩═══════════════════╝

o1o2o3是分配的实际对象。可以在每个点轻松计算可以回收多少个物体;在这种情况下,在第6行o1可以从根访问后,o3可以从o1访问,o2可以从o3访问,因此没有任何对象可以访问回收

作为旁注,我注意到你写了“但根据我至少有一个对象, t2 ,......”。如果这是你需要解决的问题,我建议放弃用指向它们的变量来命名对象的习惯;而是为每个对象提供一个虚构的id,就像我上面用o<n>所做的那样,并将变量视为指向这些对象的指针而不是它们的名称。这是因为,与指针和名称不同,对象可能包含多于或少于一个与之关联的变量,并且关联变量列表可以随时更改。

答案 2 :(得分:2)

在第5行,您调用方法Tahiti.go(),因此程序从第5行跳到10,到6时达到11。

答案 3 :(得分:1)

第11行在第6行之前执行

答案 4 :(得分:0)

堆栈图是确定哪些对象符合垃圾收集条件的最佳方法:

以下是上面代码的堆栈图:

HEAP

1000x: TahitiObj: t:2000x

2000x: TahitiObj: 5000x

3000x: TahitiObj: t: 4000x

4000x: TahitiObj: 5000x

5000x: TahitiObj: t: 6000x

6000x: TahitiObj: 3000x

堆栈

Main_Stack

args = null

t = 1000x

t2 = null

虽然Go_Stack在执行完成后将从内存中删除。为了完整,我把它保存在这里。

Go_Stack

t = 1000x

t1 = 3000x

t2 = 5000x

通过查看Main_Stack和HEAP,可以观察到我们可以直接或间接地访问所有对象。

因此,当代码执行到副主方法中的第7行时,没有对象符合垃圾收集条件。