JVM学习笔记 (5)

清除:Collector对堆内存从头到尾进行线性的遍历,如果发现某个对象在其Header中没有标记为可达对象,则将其回收

JVM学习笔记

什么是清除?

这里所谓的清除并不是真的置空,而是把需要清除的对象地址保存在空闲的地址列表。下次有新对象需要加载时,判断垃圾的位置空间是否够,如果够,就存放覆盖原有的地址。

关于空闲列表:

如果内存规整

采用指针碰撞的方式进行内存分配

如果内存不规整

虚拟机需要维护一个列表

空闲列表分配

缺点

标记清除算法的效率不算高

在进行GC的时候,需要停止整个应用程序,用户体验差

这种方式清理出来的空闲内存是不连续的,产生内存碎片,需要维护一个空闲列表

清除阶段:复制算法

背景

为了解决标记-清除算法在垃圾收集效率方面的缺陷,M.L.Minsky在1963年发表了著名的论文,“使用双存储区的Lisp语言垃圾收集器”。M.L.Minsky在该论文中描述的算法被人们称为复制算法,它也被M.L.Minsky本人成功地引入到了Lisp语言的一个实现版本中。

核心思想

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

JVM学习笔记

把可达的对象,直接复制到另外一个区域中复制完成后,A区就没有用了,里面的对象可以直接清除掉,其实堆中的的新生代就用到了复制算法

JVM学习笔记

优点

没有标记和清除过程,实现简单,运行高效

复制过去以后保证空间的连续性,不会出现“碎片”问题

缺点

此算法的缺点也是很明显的,就是需要两倍的内存空间(或者说内存浪费严重)

对于G1这种分拆成为大量region的GC,复制而不是移动,意味着GC需要维护region之间对象引用关系,不管是内存占用或者时间开销也不小

注意

如果系统中的垃圾对象很多,复制算法不是很理想。因为复制算法需要复制的存活对象数量不能太大,或者说非常低才行(老年代大量的对象存活,那么复制的对象将会有很多,效率就会很低)

应用场景

在新生代,对常规应用的垃圾回收,一次通常可以回收70% - 99%的内存空间。回收性价比很高。所以现在的商业虚拟机都是用这种收集算法回收新生代。

清除阶段:标记-整理算法(也叫标记-压缩算法)

背景

复制算法的高效性是建立在存活对象少、垃圾对象多的前提下的。这种情况在新生代经常发生,但是在老年代,更常见的情况是大部分对象都是存活对象,如果依然使用复制算法,由于存活对象较多,复制的成本也将很高。因此,基于老年代垃圾回收的特性,需要使用其他的算法。

标记-清除算法的确可以应用在老年代,但是该算法不仅执行效率低下,而且在执行玩内存回收后还会产生内存碎片,所以JVM的设计者需要再次基础上进行改进。标记-压缩算法由此诞生。

1970年前后,G.L.Steele、C.J.Chene和D.s.Wise等研究者发布标记-整理算法。在许多现代的垃圾收集器中,人们都使用了标记-整理算法或其改进版本。

执行过程

第一阶段和标记清除算法一样,从根节点开始标记所有被引用的对象

第二阶段将所有的存活对象压缩到内存的一端,按顺序排放。之后,清理边界外所有的空间。

JVM学习笔记

标记清除和标记整理的区别

标记-整理算法的最终效果等同于标记-清除算法执行完成之后,再进行一次内存碎片整理,因此,也可以把它称为标记-清除-整理算法。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpwsjy.html