上一篇:007-JVM-清除阶段算法之二:复制算法Copying
https://blog.csdn.net/fsjwin/article/details/111341315
前面两种标记收集算法和复制算法各有劣势,所以就有了此算法:标记-压缩算法Mark-Compact
1. 背景
- 复制算法的高效性是建立在存活对象少、垃圾对象多的前提下的。这种情况在新生代经常发生, 但是在老年代, 更常见的情况是大部分对象都是存活对象。如果依然使用复制算法,由于存活对象较多, 复制的成本也将很高。因此, 基于老年代垃圾回收的特性, 需要使用其他的算法。
- 标记 - 清除算法的确可以应用在老年代中, 但是该算法不仅执行效率低下, 而且在执行完内存回收后还会产生内存碎片, 所以JVM的设计者需要在此基础之上进行改进。标记一压缩(Mark - Compact) 算法由此诞生。
- 1970 年前后, G.L.SteeIe 、C.J.Chene 和D.S.Wise 等研究者发布标记 - 压缩算法。在许多现代的垃圾收集器中, 人们都使用了标记 - 压缩算法或其改进版本。
2. 收集过程
-
第一阶段和标记· 清除算法一样,从根节点开始标记所有被引用对象
-
第二阶段将所有的存活对象压缩复制到内存的一端, 按顺序排放。
-
第三阶段: 清理边界外所有的空间。
-
-
标记一压缩算法的最终效果等同于标记一清除算法执行完成后, 再进行一次内存碎片整理, 因此, 也可以把它称为标记一清除一压缩(
Mark-Sweep-compact
) 算法。 -
二者的本质差异在于标记一清除算法是一种非移动式的回收算法, 标记一压缩是移动式的。是否移动回收后的存活对象是一项优缺点并存的风险决策。
-
可以看到, 标记(其实标记的是存活的对象,特别注意)的存活对象将会被整理, 按照内存地址依次排列, 而未被标记的内存会被清理掉。如此一来, 当我们需要给新对象分配内存时,JVM只需要持有一个内存的起始地址即可, 这比维护一个空闲列表显然少了许多开销。等其他的对象需要放进来的时候就可以指针碰撞的接着放了。
-
无需空闲列表,可以指针碰撞!
-
指针碰撞(Bump the pointer):如果内存空间以规整和有序的方式分布, 即己用和未用的内存都各自一边, 彼此之间维系着一个记录下一次分配起始点的标记指针, 当为新对象分配内存时,只需要通过修改指针的偏移量将新对象分配在第一个空闲内存位置上, 这种分配方式就叫做指针碰撞( Bump the pointer) 。
3.优缺点
- 优点:
消除了标记一清除算法当中, 内存区域分散的缺点,而标记-压缩我们需要给新对象分配内存JVM 只需要持有一个内存的起始地址即可。
消除了复制算法当中, 内存减半的高额代价。 - 缺点:
从效率上来说, 标记一整理算法要低于复制算法。
移动对象的同时, 如果对象被其他对象引用, 则还需要调整引用的地址。
移动过程中, 需要全程暂停用户应用程序。即:STW
下一篇:009-JVM-对象的finalization机制
https://blog.csdn.net/fsjwin/article/details/111344414