首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > JAVA > J2SE开发 >

关于引述

2013-09-05 
关于引用本帖最后由 cup_t 于 2013-08-28 11:22:34 编辑这种情况下,a和b是否会被垃圾回收器回收呢。A.javap

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


      Test a = new Test("a");
      Test b = new Test("b");
      a.setObj(b);
      b.setObj(a);
    }
    
    System.gc();

    Thread.sleep(1000);
  }
}



输出:
gc!b
gc!b
gc!b
gc!a
gc!b
gc!a
gc!b
gc!b
gc!a
gc!a
...以下略

热点排行