码迷,mamicode.com
首页 > 编程语言 > 详细

java中的垃圾回收机制

时间:2016-05-13 12:37:06      阅读:185      评论:0      收藏:0      [点我收藏+]

标签:

1、引用计数法:老牌垃圾回收算法,通过引用计数来回收垃圾;为每个对象增加一个字段记录被引用的次数,并由运行时跟踪和更新引用的总数;

    object p = new ComparableInt32(57);

    object q = p;         我们实例化了一个对象ComparableInt32,并将其赋值给变量p,此时p引用了该对象,所以其计数器为1;然后我们又用p给变量q赋值,此时q也引用了该变量,所以其计数器变为2;

   技术分享技术分享技术分享技术分享技术分享

  缺点:不能解决循环引用的问题;需要单独的字段存储计数器,增加了空间开销;每次赋值都要更新,增加了时间开销。

2、标记-清除算法:是现代垃圾回收算法的思想基础。标记-清除算法将垃圾回收分为两个阶段:标记阶段和清除阶段。一种可行的实现是,在标记阶段,首先通过根节点,标记所有从根节点开始的可达对象。因此,未被标记的对象就是未被引用的垃圾对象。然后,在清除阶段,清除所有未被标记的对象。

  使用标记擦除法的时候,垃圾对象并不能立即被回收,相反垃圾的回收是等到内存不够使用的时候才触发;这个时候程序的执行流程将被暂时的休眠,一旦所有的垃圾回收后,才会唤醒正常的程序执行流程。标记擦除法又被称为跟踪垃圾的回收器算法,因为它跟踪所有可以直接或者间接被程序访问的对象集合;这些可以被程序直接访问的对象,有局部变量和静态变量。在回收器中,这些变量被称为根对象。一个被其他对象字段引用的对象称为可被间接访问的对象。所以可以正常访问的对象,我们称为存活对象,否则就是垃圾。

  标记擦除算法包括两个阶段,在第一个节点它首先找到所有的可访问对象并进行标记,这个阶段被叫做标记阶段;第二个阶段就是扫描堆栈上的所有未标记的对象,并进行回收内存操作,这个阶段被叫做擦除节点。

  为了区别垃圾对象和正常对象,我们需要记录每个对象的状态;所以我们可以给每个对象添加一个布尔类型的字段marked。默认情况下,所有对象刚被创建的时候都是没有被标记的,因此字段marked的初始值为false;

  标记给定的对象p以及所有可以通过p间接访问的对象,我们可以通过类似以下Mark的方法实现:

         Void Mark(object p)

    {

                   If(!p.marked)

                   {

                            p.marked = true;                       

                            For each object q referenced by p

                            Mark(q);

                   }

        }

         我们可以注意到,在这个标记的阶段,当我们遇到已经被标记的对象什么都没有做。因此,可以保证算法可以正常结束,并且只有标记了所有可访问对象后才结束。

         在第二个阶段,本算法会扫描所有的堆上的对象,来定位所有的未标记对象。在扫描的过程中,这些未标记的对象所占的内存被回收,同时每一个正常的对象的marked字段被重置为false,以便为下一次的回收做准备。

void Sweep()

{

         for each object p in the heap

                   if (p.marked)

                            p.marked = false

                   else

                            heap.Release(p);

}

  因为标记擦除法通过根对象跟踪所有的可访问对象,所以即使在循环引用的情况下也能正确的识别和回收垃圾对象。这个是其相对计数法的最大优势。然而其劣势就是执行算法的时候,需要休眠中断程序的正常执行流程,特别是需要人机交互、需要满足苛刻的实时执行要求的系统。另外一个问题就是内存碎片问题。其往往发生在已经运行过数次垃圾回收器的长时间运行的系统中。其具体的体现就是正常的对象被很多没有使用的小内存碎片隔离,其可能会导致可用内存满足所申请的内存,但是由于这些内存并不连续,导致不能正常分配内存的问题。

3、标记-压缩算法:适合用于存活对象较多的场合,如老年代。它在标记-清除算法的基础上做了一些优化。和标记-清除算法一样,标记-压缩算法也首先需要从根节点开始,对所有可达对象做一次标记。但之后,它并不简单的清理未标记的对象,而是将所有的存活对象压缩到内存的一端。之后,清理边界外所有的空间。

4、复制算法:将原有的内存空间分为两块,每次只使用其中一块,在垃圾回收时,将正在使用的内存中的存活对象复制到未使用的内存块中,之后,清除正在使用的内存块中的所有对象,交换两个内存的角色,完成垃圾回收

  缺点:不适用于存活对象较多的场合 如老年代;浪费空间

5、整合标记清理的思想结合复制算法提出新的算法:

  根据对象的存活周期的不同将内存划分为几块。一般把java堆分为新生代和老年代,这样就可以根据各个年代的特点采用最适当的收集算法。在新生代,每次垃 圾收集时都发现有大批对象死去,只有少量存活,那就选用复制算法,只需要付出少量存活对象的复制成本就可以完成收集。而老年代中因为对象存活率高、没有额外空间对他进行分配担保,就必须使用“标记-整理”算法进行回收。

参考:http://blog.csdn.net/hou478410969/article/details/7533445

http://blog.csdn.net/java2000_wl/article/details/8022293

java中的垃圾回收机制

标签:

原文地址:http://www.cnblogs.com/hpftt/p/5487234.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!