日期:2014-05-20  浏览次数:20744 次

关于引用
本帖最后由 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++) {