JVM:GC-常用算法理解

标记-清除

实现原理:
1、标记:标记出所有需要被回收的对象
2、清除:标记完成后,统一回收所有被标记的对象

图示:
在这里插入图片描述

缺点:
1、效率:标记和清除的效率都不高
2、空间:标记清除后会有大量不连续的碎片空间存在,当分配一个大对象时,很有可能因为找不到足够大的连续空间而导致第二次GC

复制算法

实现原理:将一块大内存分为两块一样大小的小内存,每次只使用一块,当这一块的内存用完,就会把还存活的对象全部移动到另一块内存【移动堆顶指针,按序分配】,然后把已经使用过的内存空间一次性清理。

图示:
在这里插入图片描述

优点:效率高,无需考虑碎片空间
缺点:可用内存变成原来的一半。在存活率较高的时候,有大量的复制操作,导致效率下降

标记-整理

实现原理:
1、标记:标记出所有需要回收的对象
2、整理:把存活的对象往一端移动,清理边界之外的内存

图示:
在这里插入图片描述

优点:效率高、没有内存碎片,相对于复制算法而言,可以使用到一整块内存,而不是一半。

分代收集

原理:根据对象存活时间的长短,分配不同的内存区域。一般分为新生代、年老代。

新生代:新生代在每次GC都会有大量对象死去,只有少量对象存活,适用于复制算法,只需付出极少的复制成本。
年老代:对象存活率高,而且没有额外空间做担保,所以一般使用 标记-清除 或者标记-整理。

HotSpot算法实现

1、为什么有stop the world?
实现垃圾回收的第一步是判断哪些对象可以被回收,hotspot通过可达性分析去判断,这项工作必须在一个能确保一致性的快照中进行,所谓的一致性是指在可达性分析的过程中,不能出现引用关系变化的情况,这点就导致GC的过程中必须要停顿所有的JAVA执行线程。

2、如何优化stop the world?
设想一下,如果可达性分析真的要去逐个检查所有对象的引用,那么势必是非常浪费时间的,而且这个时间绝对不是用户可以接受的。
实际上,虚拟机确实不需要去检查每一个上下文和全局的引用位置,虚拟机是有办法直接得知那个位置有什么引用。这就是所谓的准确式GC.

3、准确式GC的实现原理?
在HotSpot的实现中,使用了一组称为OopMap的数据结构,当类加载完成后,OopMap就会把对象某个偏移量上是什么类型的数据计算出来了。

如果所有会导致引用关系变化的指令都生成一个OopMap,那么显然要生成的OopMap太多了,那会需要大量额外的空间,导致GC的成本增大。
所以事实上,JVM也并没有为每一个指令生成OopMap,
只是在称为安全点的位置才会生成OopMap。

4、安全点的选取
目标:一般以是否能让程序长时间运行为标志设置安全点
举例:方法调用、循环跳转、异常跳转

5、如何在GC时让所有线程都跑到安全点在暂停?
抢先式中断:
在GC发生时,中断所有JAVA线程,当发现有线程不在安全点,就让他跑到安全点在暂停。
主动式中断:
就是事先设置一个标志,所有线程去轮询这个标志,当为true时,则中断挂起,轮询标志的地方和安全点重合。

6、安全区域
在一段代码的任何一个地方,都不会发生引用关系的改变,就称之为安全区域。
当发生GC时,JVM不需要管处于安全区域的线程。
当处于安全区域的线程要出安全区域时会先判断根节点枚举获取整个GC过程是否完成,如果没完成就继续等待直到收到可以离开安全区域的信号为止。

猜你喜欢

转载自blog.csdn.net/qq_28605513/article/details/85118953