Java对象循环引用,Java gc 如何回收

在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对于循环引用有一套自己的解决方案。但是话又说回来,一般实际编码中出现的循环引用不会是上面那个例子那样明显,一般都是多个对象复杂的引用导致的循环,这个时候,如果一个对象的生命周期很长,就会导致多个对象都释放不了,所以还是要特别留意对象之间的引用关系。
  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
java.lang.OutOfMemoryError: GC overhead limit exceeded是Java程序运行时常见的错误之一。它表示Java的垃圾回收器过度使用了大量的时间,却只能回收很少的内存,导致堆积的垃圾无法被及时清理,最终导致内存溢出。 这个错误通常发生在Java应用程序的堆空间非常小且被大量对象占用的情况下。当垃圾回收器花费超过98%的时间来回收垃圾,却只能回收到不到2%的堆内存时,就会触发GC overhead limit exceeded错误。这个限制是为了防止垃圾回收过程无限循环,导致程序无法正常执行。 要解决这个问题,可以尝试以下几个方法: 1. 增加堆空间大小:通过调整Java虚拟机的启动参数,增加堆空间的大小,以便容纳更多的对象。可以使用-Xmx和-Xms参数来指定最大堆和初始堆的大小。 2. 优化代码:检查代码中是否存在内存泄漏或者过度使用内存的情况。例如,及时释放不再使用的对象,避免创建过多临时对象,减少对象引用等。 3. 优化垃圾回收器设置:根据具体应用程序的需求,可以尝试使用不同的垃圾回收器或者调整垃圾回收器的参数来提高垃圾回收的效率。 总之,java.lang.OutOfMemoryError: GC overhead limit exceeded错误提示了Java程序中垃圾回收器无法有效地回收垃圾,导致内存溢出。通过增加堆空间大小、优化代码和优化垃圾回收器设置等方法,可以解决这个问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [java.lang.OutOfMemoryError: GC overhead limit exceeded问题分析及解决](https://blog.csdn.net/whc888666/article/details/128496598)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值