JVM的垃圾收集算法

JVM的垃圾收集算法

##标记清除算法(Mark-Sweep)
第一步:标记(找出内存中需要回收的对象,并且把它们标记出来
在这里插入图片描述

第二步:清除(清除掉被标记需要回收的对象,释放出对应的内存空间)
在这里插入图片描述
缺点:
标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。
(1)标记(寻找引用链)和清除(递归遍历全堆)两个过程都比较耗时,效率不高
(2)会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

标记清除算法的衍生规则之分配(动态分区分配策略)
首次适应算法(First-fit)
首次适应算法(First-fit)就是在遍历空闲链表的时候,一旦发现有大小等于需要的大小之后,就立即把该块分配给对象,并立即返回。
最佳适应算法(Best-fit)
最佳适应算法(Best-fit)就是在遍历空闲链表的时候,返回刚好等于需要大小的块
最差适应算法(Worst-fit)
最差适应算法(Worst-fit)就是在遍历空闲链表的时候,找出空闲链表中最大的分块,将其分割给申请的对象,其目的就是使得分割后分块的最大化,以便下次好分配,不过这种分配算法很容易产生很多很小的分块,这些分块也不能被使用
:临近适应算法(Next-fit)每次找到合适的空闲的分区时就记住它的位置,以便下次就从该位置开始往下查找,而不是每次都像首次适应算法那样从头开始查找
在这里插入图片描述

##标记复制算法
解决了标记清除算法的内存碎片问题
将内存划分为两块相等的区域,每次只使用其中一块。
当其中一块内存使用完了,就将还存活的对象复制到另外一块上面,然后把已经使用过的内存空间一次清除掉
缺点:
空间利用率降低
在这里插入图片描述
在这里插入图片描述
##标记整理(压缩)算法(Mark-Compact)
标记整理算法严格意义应该叫做标记清除整理算法或者标记清除压缩算法
因为他的本质就是在标记清除的基础在进行再整理,让所有存活的对象都向内存的一端移动,然后清除掉端边界外的对象
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
整理(压缩)算法分类
*随机整理:对象的移动方式和它们初始的对象排列及引用关系无关
任意顺序整理实现简单,且执行速度快,但任意顺序可能会将原本相邻的对象打乱到不同的高速缓存行或者是虚拟内存页中(理解为打乱到内存各个地方),会降低赋值器的局部性。 包括他只能处理固定大小的对象,一旦对象大小不固定,就会增加其他的逻辑。
*线性顺序:将具有关联关系的对象排列在一起
现代垃圾回收这种算法用的很少
相关的对象会进行整理,整理成一块块小区域,无法避免内存碎片
*滑动顺序:将对象“滑动”到堆的一端,从而“挤出”垃圾,可以保持对象在堆中原有的顺序
所有现代的标记-整理回收器均使用滑动整理,它不会改变对象的相对顺序,也就不会影响赋值器的空间局部性。复制式回收器甚至可以通过改变对象布局的方式,将对象与其父节点或者兄弟节点排列的更近以提高赋值器的空间局部性。

几种典型的整理算法
(优质文章挖掘:https://zhuanlan.zhihu.com/p/442743473)
*双指针回收算法:实现简单且速度快,但会打乱对象的原有布局,属于随机整理
整理前:两根指针分别位于内存的首尾段
在这里插入图片描述
第一次遍历:移动位置但是并不更新标记(知道两个指针碰撞)
在这里插入图片描述
第二次遍历:更新标记(其中一个指针继续往左移动,更新那些索引位置大于碰撞位置的GC root标记)
在这里插入图片描述
*Lisp2算法(滑动整理算法):需要在对象头用一个额外的槽来保存迁移完的地址
整理前:他是一个三指针算法,并且可以处理不同大小的对象。但是需要三次遍历,并且由于对象大小不一样,所以需要额外的空间存储,而不是直接移动(end指针的作用仅仅是用于指针碰撞结束遍历),指针具有破坏性的算法
在这里插入图片描述
第一次遍历:Free指针是为了留位置,而Scan对象是为了找存活对象
在这里插入图片描述
第二次遍历:更新对象地址(移动到哪的位置信息记录在对象本身的堆中)
在这里插入图片描述
第三次遍历:移动对象
在这里插入图片描述

*引线整理算法:可以在不引入额外空间开销的情况下实现滑动整理,但需要2次遍历堆,且遍历成本较高
*单次遍历算法:滑动回收,实时计算出对象的转发地址而不需要额外的开销
单次遍历算法的重点在于提前记录我们需要转移的位置
关键词:偏移向量,标记向量以及内存索引号
需要额外的表来记录对象的迁移位置,具体来说通过设置内存大小相同的Carl Table 来记录对象的标记位向量(对象的开始和结束位置)、偏离位向量(对象移动后的开始位置)和内存索引号
整理算法的限制,如任意顺序算法只能处理单一大小的对象,或者针对大小不同的对象需要分批处理;整理过程需要2次或者3次遍历堆空间;对象头部可能需要一个额外的槽来保存迁移的信息。

##分代收集理论
当前主流商业 JVM 的垃圾收集器,大多数都遵循了 分代收集(Generational Collection)的理论进行设计,这里需要解释下,很多博客都会把分代收集当成一种具体的垃圾收集算法,其实并不是,分代收集只是一种理论,一套指导方针,一套符合大多数程序运行实际情况的经验法则,它建立在几个分代假说之上
分代回收三大假说:
(优质文章挖掘:https://zhuanlan.zhihu.com/p/481036760)
弱分代假说:绝大多数对象朝生夕死
强分代假说:活得越久的对象,也就是熬过很多次垃圾回收的对象是越来越难以消亡的
跨代引用假说:跨代引用相对于同代引用来说仅占极少数。

依据这条假说,不应再为了少量的跨代引用去扫描整个老年代,也不必浪费空间专门记录每一个对象是否存在哪些跨代引用,只需在新生代上建立一个全局的数据结构(记忆集),这个结构把老年代分成若干小块,标识出老年代那一块内存会存在跨代引用。此后当发生Minor GC时,只有包含了跨代引用的小块内存里的对象才会被加入到GC Roots进行扫描。

目前大部分JVM采用的算法.它将内存划分为新生代和老年代.其实还有个永久代(主要存放class和Meta(原数据)的信息)
对于新生代:
采用复制算法.将新生代分为Eden Place,Survivor Place(From Place,To Place)三个空间.
每次清除时会将Eden Place和Survivor Place空间中的上一次存放的空间里的存活对象都移到另一个Survivor Place里,然后再去看前两个空间。
同时下一次存放的Survivor Place也会变成另外一个,如此循环移动。
对于老年代:
采用标记整理算法.因为老年代中每次只回收少量对象,所以采用标记整理算法.具体来说当一个存在对象在新生代中被循环次数达到了一个阙值(默认情况下为15)就会被转移到老年代中.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值