关于引用
本帖最后由 cup_t 于 2013-08-28 11:22:34 编辑
这种情况下,a和b是否会被垃圾回收器回收呢。
A.java
public class A {
B b;
public void setB(B b) {
this.b = b;
}
}
B.java
public class B {
A a;
public B(A a) {
super();
this.a = a;
}
}
然后在某个地方有如下这么一段代码,这样是不是a和b所占的内存就永远不会被释放呢?
[code=java]
A a = new A();
B b = new B(a);
a.setB(b);
------解决方案--------------------强引用并不能保证对象不被回收。垃圾回收机制除了检查对象是否被引用外,还要看对象是否被至少一个GC roots对象直接或者间接引用。GC roots对象包括以下一些类容:
1 每个线程当前的函数调用栈,从栈顶到栈底的每个函数里的局部变量。
2 静态的变量
3 被jni中引用到的变量。
所以,上面例子中两个循环引用的对象,虽然都存在一个强引用,但是不被任何GC root对象直接或者间接引用到,垃圾回收机制能够发现这个问题。
另外,为了验证这一点,特意翻看了一下android源码中GC管理这一块的代码。在MarkSweep.c这文件中,有一个void dvmHeapMarkRootSet()函数,这个函数对于GC root对象,有一些详细的说明,有兴趣的可以细看一下。
所以,java对于循环引用有一套自己的解决方案。但是话又说回来,一般实际编码中出现的循环引用不会是上面那个例子那样明显,一般都是多个对象复杂的引用导致的循环,这个时候,如果一个对象的生命周期很长,就会导致多个对象都释放不了,所以还是要特别留意对象之间的引用关系。
------解决方案--------------------循环引用会被回收。
JVM从很久以前(可能是1.2)开始就解决了这个问题。这是一个非常基本的问题,一般垃圾回收器都会考虑这个问题(关键词google:jvm circular reference)
另外做一个实验吧:
package test;
public class Test {
private Test obj;
private String iName;
Test(String name) {
iName = name;
}
void setObj(Test o) {
obj = o;
}
@Override
public void finalize() {
System.out.println("gc!" + iName);
}
public static void main(final String[] args) throws Exception {
for (int i = 0; i < 1000; i++) {