JVM 垃圾回收算法

标记-清除算法

操作

把需要清楚的对象进行一一标记

标记完成之后统一清楚

缺点

标记和清楚的执行过程效率低

清理之后形成很多的空间碎片

如果此时需要一整块大一些的空间可能就放不进去

可能就又导致新的垃圾回收以配合内存申请

时间一长这样的碎片可能是越来越密集的

 复制算法

基本复制算法

操作

把内存分为两块区域一块用于存放对象,另一块为空的内存区域

每次垃圾回收把用的区域中还存活的对象复制到空的区域中

优势

这样就不会形成内存碎片

而且效率较高

缺点

需要专门一块空间不放对象

对内存是一种浪费

HotSpot新生代 复制算法

操作

把垃圾回收分为三块区域分别是一块eden区,两块survior区域

三个大小比例是8:1:1

新的对象加入到 enden 区域 和 一块 survior区域

每次垃圾回收把这两个区域中还存活的对象放到第二个survior区域中

然后再把这个两个区域清空

原理

新生代中的对象都是 朝生夕死的,一般来说98%都会被清理掉

所以留10%的空间给能存活的2%的对象,大部分情况都足够了

分配担保机制

即使留10%也可能出现不够的情况

那么就让老年区在这种情况发现的情况下分配一下内存负担

之所以说是担保,也就是不一定总会帮忙借出内存

当达到担保的阈值的时候就不借出了

此时会执行Full GC确保能有足够的空间给新的对象

在Full GC之前都是Minor GC

标记-整理算法

操作

类似标记-清楚算法

只不过在标记之后不对需要被清楚的进行清除

而是直接把所有存活的移动到一端

诞生原因

复制算法在对象存活率较高的情况下复制就比较耗时了

而且需要用到100%内存的情况就不行了

优势

不浪费空间

不产生碎片

存活率越高效率越高

使用场景

老年代

因为老年代存活率较高

分代收集算法

特点

是当代商用虚拟机都采用的算法

也就是把内存区域划分为不同的区域

不同的区域用不同的算法

新生代用复制算法

老年代用 标记-清理 算法或 标记-整理 算法

HotSpot算法的实现

枚举GC Roots引用链

概念

枚举引用链是为了区分对象的存活信息

只有这样才能拿到对象引用信息进行进一步的收集

GC停顿 Stop the World

概念

在枚举引用链的过程中必须保证相关的引用信息不发生变化

这时候近乎要停顿整个虚拟机系统得到一个快照

所以Sun 称其为 Stop the world

可以理解要把枚举引用链整个操作做成一个原子操作

必要性

如果不停顿,那么分析出来的信息就可能是不完整的不正确的

准确式GC

来由

由GC停顿的必要性,我们知道GC停顿的频率其实是非常高的

那么就会带来时间性能的影响

那么就要考虑优化这个GC停顿,减少这个停顿带来的影响

准确式GC应运而生

概念

内存中自有某些部分是引用

如果我们整个搜索整个内存会非常低效

为此我们把是引用的内存做一个标志

让引用链枚举能直接定位到引用的内存

HotSpot中采用OppMap的数据结构来得知引用位置的信息

位置新存放在特定的地方

每次GC扫描就能通过位置信息直接定位引用位置

从而节省大量时间

安全点

来由

即使是用准确式GC

如果如果程序中的引用太多几乎每条都是的

如果在每条指令中都挂上准确式GC的OppMap

那么大量的OppMap又会占用大量的空间

而且在每条指令上都停下来GC也耽误时间

但是同时,如果仅仅在很少的引用上面挂上OppMap

那么GC的等待的时间也会过长,导致垃圾不能及时的收集

所以要在合适的点挂上OppMap

这个合适的点就是安全点

安全点特征

长时间执行的指令

因为本来就需要长时间执行

所以在这个地方挂上一个OppMap执行影响不那么明显

安全点举例

 方法调用,循环跳转、异常跳转

多线程安全点中断点

来由

多线程的时候每个线程执行到的代码为止不一样

但是我们需要Stop the world 去垃圾回收

就需要中断所有线程

而按照安全点的来由,我们希望所有线程都能在安全点中断

那么自然需要考虑办法让GC的时候所有线程中断在安全点

两种方式

抢占式中断

操作

虚拟机直接先中断所有线程

然后找到不在安全点的线程

取消这个线程的中断让它执行到安全点再中断

这样让所有线程都在安全点中断

特点

现在几乎没有虚拟机采用这种中断方式

我猜是没有后一种好

后一种直接到了合适的位置再中断

这样节省一次中断的操作

主动式中断

操作

需要垃圾回收的时候

虚拟机设置好一个标志

标志位置

安全点

新建对象之前

都要回收了,新建对象就不合适了

所以这里也能作为中断来回收垃圾

然后所有线程轮询这个标志

如果发现标志为真就把自己中断挂起

这就是主动的体现

是线程主动把自己挂起的

而不是虚拟机强制线程挂起的

原理

虚拟机在生成一个轮询的指令

这个指令让某个内存页不可读

读到这个页的线程就会发生异常

而异常的处理就是把自己中断

安全区

来由

即使有了安全点让所有线程尽快到安全点中断然后开始GC

但是安全点的方式中总是需要线程能走到安全点

而某些线程是不会走的比如blocked状态的线程就不会走

那么他们也到不了安全点

安全区应运而生解决这个问题

概念

安全区是引用关系不会发生变化的安全的区域

操作

线程走入安全区之后自己标记上安全区的标记

然后这个区域虚拟机不用管线程的转态直接就能收

唯一要管的是在线程离开安全区之前要GC完毕

如果有的线程GC没有完毕想要离开就让这个线程等在这个区域知道GC完毕再自行

思考

安全点和安全区到底用哪个呢?

如果是结合使用

那么大概就是block的线程专门用安全区的办法

那么怎么让block的线程到安全区呢

我猜是对会block的线程进行一个标记,然后等这种线程进入安全区

其他状态线程都到了安全点,然后开始GC

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值