前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >《深入理解Java虚拟机》读书笔记(五)

《深入理解Java虚拟机》读书笔记(五)

原创
作者头像
DestinySkywalker
修改2023-01-03 23:00:32
2240
修改2023-01-03 23:00:32
举报
文章被收录于专栏:用户5816045的专栏

垃圾收集算法

标记-整理法.png
标记-整理法.png

垃圾收集算法的两大类

从如何判定对象消亡的角度出发(例如,前面提到的引用计数算法和GC Roots可达性分析算法),垃圾收集算法可以划分为:

  • 引用计数式垃圾收集(Reference Counting GC)
  • 追踪式垃圾收集(Tracing GC)

这两类也常被称作“直接垃圾收集”和“间接垃圾收集”

分代收集理论

当前商业虚拟机的垃圾收集器实现大多遵循“分代收集(Generational Collection)”理论,该理论包含三条分代假说:

  • 弱分代假说:绝大多数对象都是朝生夕灭的
  • 强分代假说:熬过越多次垃圾收集过程的对象就越难以消亡
  • 跨代引用假说:跨代引用相对于同代引用来说仅占极少数

依据“弱分代假说”和“强分代假说”,在兼顾垃圾收集器的时间开销和内存空间的有效利用的基础上,设计者将对象依据其存亡特征的不同的放在不同的区域中(一般至少将Java堆划分成了“新生代”和“老年代”),因而才有“Minor GC”、“Major GC"、“Full GC”这样回收类型的划分,也才能够针对不同内存区域安排与里面存储对象存亡特征相匹配的垃圾收集算法(“标记-复制算法”、“标记-清除算法”、“标记-整理算法”等)

依据“跨代引用假说”,设计者不再需要针对跨代引用的内存回收在固定的GC Roots之外,再额外遍历整个老年代中所有对象来确保可达性分析结果的正确性;而仅需再新生代上建立一个全局的数据结构(一般称之为“记忆集”,Remembered Set),标识出老年代的哪一块内存会存在跨代引用,当发生Minor GC时,只有包含了跨代引用的小块内存里的对象才会加入到GC Roots进行扫描

不同GC名词的含义

根据垃圾收集动作是否覆盖整个堆和方法区,GC分为部分收集(Partial GC)和整堆收集(Full GC),而部分收集又可细分为新生代收集(Minor GC、Young GC)、老年代收集(Major GC、Old GC)、混合收集(Mixed GC)

  • Partial GC:指目标不是完整收集整个Java堆的垃圾收集
  • Minor GC / Young GC:指目标只是新生代的垃圾收集
  • Major GC / Old GC:指目标只是老年代的垃圾收集,目前只有CMS收集器会有单独收集老年代的行为
  • Mixed GC:指目标是收集整个新生代以及部分老年代的垃圾收集,目前只有G1收集器会有这种行为
  • Full GC:收集整个Java堆和方法区的垃圾收集

标记-清除算法

标记-清除算法,一种非移动式的回收算法(较于后面将会提到的标记-整理算法),算法分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后,统一回收所有被标记的对象,也可以反过来,标记存活的对象,统一回收未被标记的对象

标记-清除法.png
标记-清除法.png

缺点:

  • 一、因为“标记”针对整个回收区域的对象,所以执行效率随着对象数量增长而降低,效率不稳定
  • 二、存在内存空间碎片,回收后的内存零散分布,随着碎片的逐渐增多碎片体积的减小,后期新生对象的内存分配将分配不到足够连续的内存,而导致频繁的触发GC动作

标记-复制算法

标记-复制算法,为解决标记-清除算法存在的面对大量可回收对象时执行效率低的问题,采用“半区复制”的方式:将可用内存按容量划分为大小相等的两块,每次只使用其中一块,当这一块用完后,就将存活的对象复制到另一块区域上,而后将已使用的内存空间一次性清理掉

标志-复制法.png
标志-复制法.png

缺点:

  • 一、对于存在大量存活对象的情况,对象的拷贝迁移开销太大
  • 二、“半区复制”对于寸土寸金的内存区域来说太过浪费,即使不是按照1:1的比例实现“半区复制”,内存的浪费依然是其一大缺点
  • 三、存活的对象可能超过保留区域的内存大小,为此不得不设置分配担保的策略

现代商用的Java虚拟机大多采用这种方式进行新生代的回收,依据“弱分代假说”所划分出来的“新生代”中的对象大多朝生夕灭,减少了因大量存活对象导致的复制迁移的开销

同时,还是依照“朝生夕灭”的特征,又出现了解决内存划分不合理导致内存浪费问题的“Appel式回收”:将新生代采用8:1的比例划分成一块较大的Eden区和两块Survivor空间,每次分配内存只使用Eden和其中一块Survivor,发生垃圾收集时,将Eden和Survivor中仍然存活的对象一次性复制到另外的一块Survivor空间上,然后直接清理掉Eden和已用过的那块Survivor空间

此外,“Appel式回收”对分配担保也做了安全设计:当Survivor空间不足以容纳一次Minor GC之后存活的对象时,将依赖老年代,即这些对象将通过分配担保机制直接进入老年代

标记-整理算法

标记-整理算法,一种移动式的回收算法(较前面提到过的标记-清除法),是针对老年代对象存放特征设计出的一套算法:其中标记过程仍与标记-清除算法一致,区别在于,标记-整理法并不直接清理可回收对象,而是让所有存活对象都向内存空间一端移动,而后,将边界之外的内存回收掉

标记-整理法.png
标记-整理法.png

标志-整理法,由于“整理”的需要,存在对象移动,对于老年代这种有大量存活的对象的内存区域来说,移动对象就意味着需要更新所有引用这些对象的地方,这种操作则不得不在被称为“Stop The World”的全程暂停用户应用程序的情况下进行,因此造成了用户应用程序一定程度的延迟

同标记-清除算法比较一下,由于没有“整理”的动作,弥散于堆中的存活对象导致的空间碎片话问题就只能依赖更为复杂的内存分配器和内存访问器来解决(类似于硬盘通过分区表实现存储大文件不需要使用物理连续的内存空间),这势必会直接影响应用程序的吞吐量

对比两种算法,是否移动对象都存在弊端:从内存的使用角度看,移动则内存回收时复杂,不移动则内存分配复杂;从垃圾收集的停顿时间看,不移动对象停顿时间更短,甚至不需要停顿,不移动对象则吞吐量较高

因此,HotSpot虚拟机里,关注吞吐量的Parallel Scavenge收集器是基于标记-整理算法的,而关注延迟的CMS收集器则是基于标记-清除算法的

另外,CMS还提供了一种“和稀泥式”的配置参数,可以不再内存分配和访问上增加太大负担,做法是:让虚拟机平时大多数时间都采用标记-清除算法,暂时容忍内存碎片,当内存碎片化程度达到一定比例时,再采用标记-整理算法收集一次,以便获得更规整的内存空间

缺点:

  • 存在STW,对用户应用程序造成延迟

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 垃圾收集算法
    • 垃圾收集算法的两大类
      • 分代收集理论
        • 不同GC名词的含义
        • 标记-清除算法
        • 标记-复制算法
        • 标记-整理算法
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档