[英]Why does System.gc() recycle only one object in this code?
在下面的代码中,只有一个对象在运行时从堆内存中清除(通过调用System.gc()
)。 为什么只回收一个对象?
class A{
A a;
public A(A a){
this.a=a;
}
public static void main(String args[]){
A a1=null;
A a2=new A(new A(null));
A a3=new A(a2);
a1=a3;
a1.a=new A(null);
a2.a=null; //Line12
System.gc();
}
}
我认为尝试用Java固定确切的GC收集时间是很可怕的,但是无论如何..
Java垃圾回收在对象可访问性上起作用。 如果对象是高度可访问的-也就是说,如果可以从可访问性或已知根(包括局部变量)的任何路径访问它,则该对象将无法回收1 。
考虑一下这种细分,其中W,X,Y,Z代表A的不同实例 。我用来显示任何特定A的语法是instance {a-> instance}
,其中a
表示成员变量。 请记住,每个new
都会创建一个不同的实例,并且对象值的分配不会创建新对象(因此, 相同的Y对象 -现在由a1和a3共享-在a1.a=new A(null)
分配期间被修改)。
A a1=null; // a1 = null
A a2=new A(new A(null)); // a2 = W {a-> X}
A a3=new A(a2); // a3 = Y {a-> W}
a1=a3; // a1 = a3 = Y {a-> W}
a1.a=new A(null); // a1 = a3 = Y {a-> Z}
a2.a=null; // a2 = W {a-> null}
System.gc();
// Then:
// a1 = a3 = Y {a-> Z} (Expanding: Y {a-> Z {a-> null}})
// a2 = W {a-> null}
因此,最后变量a1和a3- 可达根 -是“引用” Y {a->Z}
而a2是“引用” W {a->null}
。 这意味着W,Y和Z仍然都是很容易到达的(Z可以通过Y很大地到达),并且不适合在Java-land 2中进行回收。
System.gc()
行上仅X不再可访问。 但是,这并不意味着X将是垃圾回收,即使有明确的GC调用-它只是意味着X是有资格在未来某个时间点进行回收。
当然,函数结束后,所有局部变量都不再是可访问性根,并且A对象都不是强可访问性,从而使它们都符合条件:)
1使用对象的可达性仍然讨论GC作品即使不使用传统的马克和扫描为基础的方法(这是在JVM中常见)作为规则同样适用于任何正常GC系统时:如果有机会的话可以将一个物体被访问,则无法回收。 相反,如果无法访问对象,则应将其回收。
2确定可达性根源的规则因语言/运行时间而异。 例如,在某些极端情况下,C#/ CLR处理存在细微的差异。
正如其他人指出的那样,当一个对象既不能直接作为变量的值访问,也不能因为另一个可访问对象对其进行引用而间接访问时,就可以收集该对象。 让我们一次遍历几行代码,看看随着时间的推移对象引用图的外观。
A a1=null; // 1
A a2=new A(new A(null)); // 2
A a3=new A(a2); // 3
a1=a3; // 4
第1行没有太大的作用,我们甚至可以消除它,并将第4行更改为A a1 = a3
而没有任何不同的结果。 线2台a2
的值到一个新的实例的引用A
,称之为α,其a
字段是的第二个新的实例的引用A
,β调用它。 第3行创建的新实例A
,称之为γ,它的a
领域是α的参考。 因此,参考了所有的α,β和γ。 第4行将a1
的值作为γ的参考。 注意:
a2
,只要可以访问γ,则可以间接访问; a1
和a3
。 下一个,
a1.a=new A(null); // 5
a1.a = new A(null)
更新γ是a
领域是一个新的实例A
,δ调用它。 现在:
a2
直接访问,而不能通过其他任何方式间接访问; a1
和a3
访问γ; 和 最后,
a2.a=null; // 6
现在,删除对β的最后一个引用。 仍然引用α,γ和δ。
a2
可直接访问; a1
和a3
访问γ; 和 由于根本无法访问β,因此它是垃圾收集的候选对象。 System.gc()
的Javadoc说:
运行垃圾收集器。 调用此方法表明,Java虚拟机将花费更多精力来回收未使用的对象,以使它们当前占用的内存可用于快速重用。 当控制从方法调用返回时,虚拟机将尽最大努力回收所有丢弃的对象。
因此,当我们到达
System.gc(); // 7
该系统可以但不要求收集β。 可以肯定地说,β将通过“尽最大努力回收所有丢弃的物体”来收集,但这并不是保证。
检查以下评论:
public static void main(String args[]){
A a1=null;
A a2=new A(new A(null)); //a2.a = new A(null); //line 3
A a3=new A(a2); //a3.a = a2
a1=a3; //a1 = a3
a1.a=new A(null); //a1.a = a3.a = null; a2 is still referenced
a2.a=null; //Line12 //a2.a = null => object at line 3 is cleared after gc
//because it is not referenced anymore by any variable.
System.gc();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.