您的位置:首页 > 编程语言 > Java开发

Java虚拟机--垃圾回收算法(六)

2017-03-27 23:07 162 查看
知识点的梳理:

名词解释:
可达对象:指通过根对象进行引用搜索,最终可以达到的对象;
不可达对象:通过根对象进行引用搜索,最终没有被引用到的对象;
新生代:存放年轻对象的堆空间。年轻对象指刚刚创建的,或者经历垃圾回收次数不多的对象;
老年代:存放老年对象的堆空间。该对象经历过多次垃圾回收依然存活的对象;

新生代对象特点:Java虚拟机会将所有的新建对象放入这里。这里的对象朝生夕灭,大约90%的新建对象被很快回收,适合复制算法;

老年代对象特点:几乎所有对象都是经过几次回收后依然得以存活。适合使用标记压缩算法;
  

认识垃圾回收
名称:垃圾回收(Garbage Collection,简称GC);

能力:自动回收内存中,不在被使用的对象;
能力思想:从根节点开始是否可以访问到这个对象,如果可以,说明该对象正被使用,如果从所有的根节点都无法访问到某个对象,说明此对象不再被使用,此对象可回收。

问题:垃圾回收时的停顿现象
为了让回收器可以高效执行,会要求系统进入一个停顿状态。目的是终止所有应用线程,这样系统才不会生成新的垃圾。同时该操作保证了系统状态在某一个瞬间的一致性,也利于垃圾回收器更好地标记垃圾对象。
停顿产生时,整个应用程序会被卡死,没有任何响应,这个停顿也叫"stop-the-world(STW)"

引用计数法(Reference Counting)

能力:对于一个对象A,只要有任何一个对象引用了A,则A的引用计数器加1,当引用失效时,计时器减一。只要对象A的引用计数器为0,则对象A不再可用;
计数器的实现:为每个对象配备一个整型的计数器即可;

缺点:

无法处理循环引用的情况。Java的垃圾回收器没有使用这种算法;

循环引用问题描述:有对象A和对象B,对象A中含有对象B的引用,对象B中含有对象A的引用。此时,对象A和B的引用计数器都不为0.但是,在系统中,却不存在任何第3个对象引用A或B。也就是说,A或B都是回收对象,但它们相互引用,使垃圾回收期无法识别,引起内存泄露



引用计数器在引用产生和消除的时候,伴随一个加减法操作,会影响系统性能;

标记清除法(Mark-Sweep)
能力:将垃圾回收期分为两个阶段:标记阶段和清除阶段。在标记阶段,通过根节点,标记所有从根节点开始的可达对象。未被标记的对象就是未被引用的垃圾对象,会在清除阶段被清除。

缺点:
在清除对象时,会产生空间碎片;

图示:下图显示了两个根节点的引用过程,系统会回收所有的不可达空间;回收后的空间是不连续的。对于大对象的内存分配,不连续的内存空间会影响效率;



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

适用场景:适用于新生代。在新生代,垃圾对象通常会多于存活对象;

能力图示:



优点:
如果系统中,垃圾对象很多,复制算法需要复制的存活对象相对就会少,复制算法的效率就会很高;
对象是在被回收时,统一被复制到新内存空间的,不存在空间碎片问题;

缺点:
复制算法的代价是系统内存折半!

Java中的复制算法:
能力背景:Java在新生代串行垃圾回收器中使用了该算法的思想;新生代分为eden空间,from空间,to空间3部分。其中from和to空间可以视为用于复制的两块大小相同,地位相等,且可进行角色互换的空间块。from和to也称为survivor空间,即幸存者空间,用于存放未被回收对象;

能力:垃圾回收时,eden空间中的存活对象被复制到未使用的survivor空间中(假设是to),正在使用的survivor空间(假设是from)中的年轻对象也会被复制到to空间中(大对象,或者老年对象会直接进入老年代,如果to空间已满,则对象也会直接进入老年代)。此时,eden空间和from空间中的剩余对象就是垃圾对象,可以直接清空,to空间则存放此次回收后的存活对象



标记压缩法(Mark-Compack)
能力:从根节点开始,对所有可达对象做一次标记。之后,将所有存活对象压缩到内存的一端,并清理边界外所有空间

适用场景:老年代中的大部分对象都是存活对象,适合使用此算法;

能力图示:



分代算法(Generational Collecting)

能力:将内存区间根据对象的特点分成几块,根据每块内存区间的特点,使用不同的回收算法,提高垃圾回收的效率;

能力思想:



技能:

卡表数据结构:虚拟机使用此技能来应对新生代内存的高频率回收。卡表为一个比特位集合,每个比特位用来表示老年代的某一区域中的所有对象是否持有新生代对象的引用。这样在新生代GC时,不用花费大量时间扫描老年代对象,来确定引用关系。可以先扫描卡表,只有当卡表的标记位为1时,才需要扫描给定区域的老年代对象,而卡表位为0的区域内的老年代对象,一定没有新生代的引用。

图示:



  

分区算法

能力:将整个堆空间划分成连续的不同小区间。每一个小区间独立使用,独立回收;
能力分析:在相同条件下,堆空间越大,一次GC花费的时间越长,停顿时间也越长。为了更好地控制GC产生的停顿时间,将一块大的内存区域分割成多个小块,根据目标的停顿时间,每次合理地回收若干个小区间,而不是整个堆空间,从而减少一次GC所产生的停顿;

能力图示:



优点:
可以控制一次回收多少个小区间;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: