java对象之间相互循环引用实例
2016-04-15 12:29
330 查看
在C++中使用过智能指针的同学们应该都清楚智能指针对C++中内存管理带来的极大便利,但是也会引入一些头疼的问题,比如智能指针带来的循环引用的问题,这个问题在之前的项目中一直没有很好的解决。
最近参与到android的项目开发,对java的内存的管理有了一个初步的了解,很容易想到了循环引用的问题。比如下面这个例子:
public void buidDog()
{
Dog newDog = new Dog();
Tail newTail = new Tail();
newDog.tail = newTail;
newTail.dog = newDog;
}
在这里,newTail中拿着对newDog的引用,newDog中拿着对newTail的引用。如果newDog要被回收,前提是newTail被先回收,这样才能释放对newDog的引用。但是反回过来,newTail要被回收的前提是newDog要被先回收。当buildDog函数退出后,看起来垃圾回收管理似乎就始终无法回收这两个实际已经不再需要的对象。
垃圾回收机制究竟能否解决循环引用这一困境,带着这个疑问找了一些资料,找到了一个比较满意的解释。在《Java Platform Performance: Strategies and Tactics》这本书的附录A中有一处说明,这本书出自sun公司java团队员工,应该算比较权威的。其中有这样一段(http://java.sun.com/docs/books/performance/1st_edition/html/JPAppGC.fm.html#997428):
“It's important to note that not just any strong reference will hold an object in memory. These must be references that chain from a garbage collection root. GC roots are a special
class of variable that includes
Temporary variables on the stack (of any thread)
Static variables (from any class)
Special references from JNI native code”。
这段话可以简单的理解就是强引用并不能保证对象不被回收。垃圾回收机制除了检查对象是否被引用外,还要看对象是否被至少一个GC roots对象直接或者间接引用。GC roots对象包括以下一些类容:
1 每个线程当前的函数调用栈,从栈顶到栈底的每个函数里的局部变量。
2 静态的变量
3 被jni中引用到的变量。
所以,上面例子中两个循环引用的对象,虽然都存在一个强引用,但是不被任何GC root对象直接或者间接引用到,垃圾回收机制能够发现这个问题。
另外,为了验证这一点,特意翻看了一下android源码中GC管理这一块的代码。在MarkSweep.c这文件中,有一个void dvmHeapMarkRootSet()函数,这个函数对于GC root对象,有一些详细的说明,有兴趣的可以细看一下。
所以,java对于循环引用有一套自己的解决方案。但是话又说回来,一般实际编码中出现的循环引用不会是上面那个例子那样明显,一般都是多个对象复杂的引用导致的循环,这个时候,如果一个对象的生命周期很长,就会导致多个对象都释放不了,所以还是要特别留意对象之间的引用关系。
最近参与到android的项目开发,对java的内存的管理有了一个初步的了解,很容易想到了循环引用的问题。比如下面这个例子:
public void buidDog()
{
Dog newDog = new Dog();
Tail newTail = new Tail();
newDog.tail = newTail;
newTail.dog = newDog;
}
在这里,newTail中拿着对newDog的引用,newDog中拿着对newTail的引用。如果newDog要被回收,前提是newTail被先回收,这样才能释放对newDog的引用。但是反回过来,newTail要被回收的前提是newDog要被先回收。当buildDog函数退出后,看起来垃圾回收管理似乎就始终无法回收这两个实际已经不再需要的对象。
垃圾回收机制究竟能否解决循环引用这一困境,带着这个疑问找了一些资料,找到了一个比较满意的解释。在《Java Platform Performance: Strategies and Tactics》这本书的附录A中有一处说明,这本书出自sun公司java团队员工,应该算比较权威的。其中有这样一段(http://java.sun.com/docs/books/performance/1st_edition/html/JPAppGC.fm.html#997428):
“It's important to note that not just any strong reference will hold an object in memory. These must be references that chain from a garbage collection root. GC roots are a special
class of variable that includes
Temporary variables on the stack (of any thread)
Static variables (from any class)
Special references from JNI native code”。
这段话可以简单的理解就是强引用并不能保证对象不被回收。垃圾回收机制除了检查对象是否被引用外,还要看对象是否被至少一个GC roots对象直接或者间接引用。GC roots对象包括以下一些类容:
1 每个线程当前的函数调用栈,从栈顶到栈底的每个函数里的局部变量。
2 静态的变量
3 被jni中引用到的变量。
所以,上面例子中两个循环引用的对象,虽然都存在一个强引用,但是不被任何GC root对象直接或者间接引用到,垃圾回收机制能够发现这个问题。
另外,为了验证这一点,特意翻看了一下android源码中GC管理这一块的代码。在MarkSweep.c这文件中,有一个void dvmHeapMarkRootSet()函数,这个函数对于GC root对象,有一些详细的说明,有兴趣的可以细看一下。
所以,java对于循环引用有一套自己的解决方案。但是话又说回来,一般实际编码中出现的循环引用不会是上面那个例子那样明显,一般都是多个对象复杂的引用导致的循环,这个时候,如果一个对象的生命周期很长,就会导致多个对象都释放不了,所以还是要特别留意对象之间的引用关系。
相关文章推荐
- 第一个java应用程序
- java实现双向链表
- Eclipse将普通的项目转成Web项目
- Struts 2配置 JSON JAVA生成json数据与 json数据解析
- eclipse的文件同步插件
- Java中值传递和引用传递实例
- 【Spring实战】—— 9 AOP环绕通知
- Open JDK 建立SSL失败的问题
- 转:如何查看MyEclipse包含的Eclipse的版本号
- java中解决构造函数中成员变量和形参重名的问题
- java实现栈
- spring4.2+spring mvc +spring data+jpa+hibernate的程序构架
- java中静态代码块的用法 static用法详解
- 转:myeclipse和eclipse的区别和联系,以及版本间的对应关系
- springmvc向页面传值时对list去重
- 转: MyEclipse 10.0,9.0,8.0 下添加jadClipse反编译插件
- eclipse常用20个快捷键
- Java并发编程:Lock
- spring aop中的propagation的7种配置的意思
- 基于配置的Spring AOP