深入理解JVM之垃圾收集器

垃圾收集器

书到用时方恨少,事非经过不知难!本文参考《深入理解JVM》周至明著。由于写作水平和写作时间有限,本中存在不妥之处,还请大家多多留言。

判定对象死亡

  • 引用计数算法

思想:创建对象时并给其添加一个引用计数器,当某一地方引用它时,计数器值+1,当引用失效时,计数器值-1;任何计数器为0的对象就不可能再被使用。

缺点:难解决对象之间相互循环引用的问题。

  • 可达性分析算法(主流商用语言:Java,C#等)

思想:通过一系列 “GC Roots” 对象作为起始点,从这些节点向下搜索,搜索经过的路径称为引用链(Reference Chain),当某一个对象到 GC Roots 没有任何引用链连接时,则证明对象不可能再被引用。

  • Java语言中,GC Roots的对象
  1. 虚拟机栈中引用对象。

  2. 方法区中类静态属性引用的对象。

  3. 方法区中常量引用的对象。

  4. 本地方法栈中JNI(一般指Native方法)引用的对象

  • 垃圾收集算法

  • 标记-清除算法(Mark-Sweep)

过程:分为2个阶段,标记和清除。首先标记处所有需要清理的对象,标记完成之后,统一回收被标记的所有对象。

不足

  1. 效率:标记和清除效率都不高。
  2. 空间问题:标记清除完之后,可能产生大量的不连续内存碎片,会导致分配内存较大对象,无法找到连续空间内存,从而提前触发一次垃圾收集。

工作如下图所示

  • 复制算法

基本思想:将可用内存按容量分为大小相等2块(用A、B代指),每次先使用A,当A使用完了,就A现存活对象复制到B中,然后一次将A的内存空间清空。

优点:不考虑内存碎片等复杂情况。

缺点:将内存缩小为原来一半。

工作如下图所示:

  • 标记-整理算法

基本思想:先标记完所有可回收对象,然后让存活对象向一端移动,最后清理掉剩下的内存。

“标记-整理算法”如下图所示:

  • 分代收集算法

当前商业虚拟机垃圾收集都采用“分代收集”(Generational  Collection)算法,根据对象存活周期不同划分为几块;一般将其分为新生代和老年代。

新生代特点:每次垃圾收集时都有大批对象死去,只要少量存活。(采用复制算法)

老年代特点:对象存活率高、没有额外空间对它进行分配担保,就采用“标记-清理”或“标记-整理”算法来进行回收。

分配担保机制:某一空间内存(譬如:新生代)不够时,需要依赖另一空间(譬如:老年代)进行担保。如生活中去银行借款,需要一个担保人一样。

HotSpot的算法实现

在安全点/安全域中使用OopMap结构完成根节点枚举。

  • 枚举根节点

在HotSpot 实现根节点枚举时,遇到2个问题:1、数据一致性:在判定对象过程中必须保证对象引用关系不变。2、消耗时间多:逐个检查引用。

解决办法:通过使用一组称为OopMap的数据结构,在类加载、编译过程中确定偏移量及对应的数据类型,在特定位置记录栈和寄存器中哪些位置是引用。

  • 安全点

一般在方法调用、循环跳转、异常跳转等“长时间执行”的地方,才会产生安全点(Safepoint)。即指上面提到的“特定位置”。

  • 安全域

在一段代码中,引用关系不会发生变化。

垃圾收集器

以垃圾收集线程与用户线程为例:

并行(Parallel):多条垃圾收集线程并行工作。

并发(Concurrent):用户线程与垃圾收集线程同时进行。

下图展示7种收集器,2个收集器之间存在连线,表名可搭配使用。

  • Serial收集器

特点:单线程的收集器,在它进行垃圾收集时,必须暂停其他所有工作线程,直到它收集结束。

适用场景:JVM 运行在Client模式下的默认新生代收集器。

  • ParNew收集器

特点:使用多条线程进行垃圾收集。

适用场景:Service模式下的JVM中首选的新生代收集器。

  • Paraller Scavege收集器

特点:新生代收集器;一个可控制的吞吐量。即吞吐量=运行用户代码时间/(垃圾收集时间+运行用户代码时间)。

GC自适应的调节策略(GC Ergonomics):虚拟机根据当前系统运行情况收集性能监控信息,动态调整参数。

  • Serial Old收集器

​​​​​​​使用“标记-整理”算法,单线程收集器。

  • Paraller Old收集器

​​​​​​​使用多线程和“标记-整理”算法

  • CMS 收集器(Concurrent Mark Sweep)

​​​​​​​目标:获取最短回收停顿时间。基于“标记-清除”算法。

  • 过程
  1. 初始标记:标记GC Roots关联到的对象,速度块。
  2. 并发标记(耗时):进行GC Roots Tracing的过程。
  3. 重新标记:修正用户程序运行过程中,导致标记产生变动的对象的标记记录。
  4. 并发清除(耗时)
  • 缺点
  1. CMS无法处理浮动垃圾(Floating Garbage):GC下一次清理浮动垃圾。在并发清理阶段,用户线程运行时产生的新垃圾,即为浮动垃圾。
  2. 采用“标记-清除”算法,产生大量的控件碎片。解决:为其提供内存碎片合并的参数。
  • G1收集器(Garbage-First)

​​​​​​​在JDK1.7之后采用此收集器,用于服务端应用的垃圾收集器。

特点

  1. 并发与并行
  2. 分代收集
  3. 空间整合
  4. 可预测停顿。
  • 过程
  1. 初始化标记
  2. 并发标记:耗时长,与用户线程并发执行。
  3. 最终标记
  4. 筛选回收

猜你喜欢

转载自blog.csdn.net/MK456/article/details/83688140
今日推荐