现在的位置: 首页 > 综合 > 正文

深入理解Java的垃圾回收机制

2013年03月19日 ⁄ 综合 ⁄ 共 3176字 ⁄ 字号 评论关闭

  1.当一个对象不再被程序所引用时,它所使用的堆空间可以被回收,以便被后续的新对象使用;

  2.GC需要实现的功能

    (1)判断哪些对象不再被程序所引用

    (2)释放无用对象的内存

    (3)执行无用对象的终结方法

    (4)移动活动对象在堆中的位置,减少堆内存中的碎片《因为对象在堆中的内存不是连续分配的,因此可能的情况是,需要为一个新的对象分配内存空间时,堆中的剩余空间足够为新对象分配内存,但是因为这些空闲的区域不连续,导致需要扩大堆的内存空间》

  3.使用GC的好处

    (1)提高程序员的编程效率,程序员不需要编写Java代码释放对象的内存

    (2)提高Java程序的安全性,避免程序员因为忘记释放无用对象的内存空间而造成的内存泄漏情况,避免程序员因为误放内存而导致的内存访问冲突问题。

  4.垃圾收集算法

    4.1 任何垃圾收集算法都需要完成两件事情:

    (1)检测出垃圾对象

    (2)回收垃圾对象所使用的堆空间并归还给java程序

    4.2 检测垃圾对象的解决方法

         (1) 建立一个根对象的集合,检查从根对象开始的可触及性,对于GC而言,根对象始终是可触及的,如果从根对象到某个对象之间存在引用路径,则该对象就是可以触及的,是“活动的对象”,无法被触及的对象不会影响程序的执行,因此可以被GC作为垃圾回收

         (2)检测垃圾对象的具体实施算法

                 计数和跟踪,前者已经被淘汰,所以不再赘述;

           4.2.1 标记并清除收集器

               a. 原理:跟踪收集器追踪从根节点开始的对象引用图,在追踪过程中遇到的对象以某种方式打上标记,追踪结束后,未被标记的对象就是无法触及的,可以被GC收集。

               b.具体实施:跟踪垃圾收集器采用“标记并清除”算法,这是垃圾收集过程的两个阶段:在标价阶段,GC遍历引用树,标记遇到的对象;在清除阶段,GC会释放每一个没有被标记的对象的内存空间

               c.标记并清除回收器的一些策略

               A.移动对象内存的策略

                 GC需要移动活动的对象来减少堆中的碎块,标记并清除收集器通常使用两种策略:压缩和拷贝

                 A.1 压缩的实施方案为:将活动的对象移动到堆的一端,这样,堆的另一端会出现一个大的连续空闲区,这样需要在移动对象时改变对象的引用,解决这个问题的方案是,采用间接对象引用表,表中的每一项保存指向对象实际保存位置的句柄,对象的引用指向这些句柄,当GC移动活动的对象时,只需要改变对象的句柄,不过缺点是找到对象的实际保存位置需要两次指针操作

                 A.2拷贝的实施方案为:把所有的活动对象移动到一个新的区域,移动到新的区域之后,这些对象之间不再有空隙,这种方法的优势在于对象可以在从根对象开始的遍历过程中随着发现而被拷贝,不再有标记和清除的区分

                  具体算发“停止并拷贝”

                   (1)堆被分为两个区域,任何时候都只能够使用其中的一个区域,对象在同一个区域中分配,直到这个区域被耗尽,此时,程序执行中止(GC线程执行时,执行Java程序的线程必须终止,因此一个时刻只能够有一个线程使用CPU),GC遍历堆,遍历中遇到的活动的对象被拷贝到另外一个区域中,当停止和拷贝过程结束后,程序恢复执行,从新的对区域中分配内存,直到这个新的区域也被占用完毕,这样程序会继续中止,将新堆中活动的对象拷贝到原来的堆区域中

                   (2)存在的问题

                          堆空间被分为两个部分,每次只能够使用其中的一半

                B.按代分配的策略

                  B.1思想

                      (1)大多数线程创建的大部分对象都具有很短的生命周期

                      (2)一些对象也会有比较长的生命周期

                  B.2简单采用拷贝算法的GC浪费效率的一个主要原因在于,它们每次都把生命周期很长的对象来回拷贝,消耗大量的时间

                  B.3解决方案:GC把对象按照寿命来分组,更多地拷贝那些短暂出现的年幼的对象

                  B.4具体实施:堆被划分成为两个或者更多的子堆,每一个子堆为一“代”对象服务,最年幼的那一代(子堆)进行最频繁的垃圾收集(即主要将拷贝工作集中在最年轻的子堆空间中),如果某个对象经过很长时间没有被收集,则这个对象需要从年轻的子堆中迁移到年长的子堆中去

                C.自适应策略  指GC根据不同的具体情况采用不同的算法    

 

                D.垃圾回收的火车算法

                  D.1 垃圾回收的不足

                    (1) 垃圾收集算法有一个潜在的缺点,即执行GC线程时需要中止执行Java程序的线程,这样有时甚至会让用户感觉到;

                    (2) 另外,执行GC线程可能会使程序对用户事件响应迟钝,这样不能够满足实时系统的需求。

                  D.2 垃圾收集采用的方法:渐进式收集算法 

                    (1) 核心思想:不试图一次性发现并回收所有不可触及的对象,而是每次发现并回收一部分

                    如果每次都只有堆的一部分执行垃圾收集,每一次收集会持续较短的时间,这样就可以让JVM适合实时环境,提供让人满意的用户环境。  

                    (2) 这种渐进的垃圾收集非常适合按代垃圾收集器,因为按代的垃圾收集器将堆空间划分为不同的区域,每一个区域都有自己的子堆,按代的垃圾收集器在年幼的子堆中比年长的子堆中活动更频繁     

                     (3) 火车算法的目的是在成熟对象空间提供限定时间的渐进收集

            4.3 对象的终结方法

                  GC在回收无用对象的堆空间之前,首先要执行无用对象的终结方法,通过执行这些终结方法,可能会使对象从可恢复状态转为可触及状态,终结方法的存在使垃圾回收线程的过程更为复杂

                  (1)首先,GC需要通过扫描检测出不再被引用的对象,然后,它需要检查出不再引用的对象是否声明了终结方法,在执行所有的终结方法之后,GC线程需要进行第二次扫描,因为终结方法可能会“复活”某些不再被引用的对象,使它们再次被引用,最后,垃圾收集器会释放在第一次和第二次扫描中发现的都没有被引用的对象。

                  (2)终结方法由GC执行,因此终结方法具有一定的不确定性,即终结方法是否执行,何时执行,都不能够确定,因此,不能让程序的正确性依赖于终结方法。

                 4.4 对象的状态

                   对象的状态分为三种:可触及状态,可恢复状态和不可触及状态

                  (1)只要Java程序中有任何变量引用这个对象,该对象就处于可触及状态,如果没有任何变量引用这个对象,对象就处于可恢复状态,如果GC执行了所有的终结方法之后,对象仍然没有转为可触及状态,则对象会进入不可触及状态,此时对象不会对程序造成任何影响,可以被GC回收

                  

抱歉!评论已关闭.