第3章-垃圾收集器与内存分配策略

本章介绍了垃圾收集的算法,几款JDK1.7中的垃圾收集器特点以及动作原理。通过代码验证实例验证了Java虚拟机中自动分配及回收的主要规则。

哪些内存需要回收?什么时候回收?如何回收?

对象已死吗

引用计数算法

给对象中添加一个引用计数器,每当有一个地方引用它时,计数器值加1,失效计数器就减1。
弊端:它很难解决对象之间相互循环引用的问题

可达性分析算法

通过一系列的“GCRoots“的对象作为起点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GCRoots没有任何引用链相连时,则证明此对象是不可用的。
GCRoots对象包括:

  • 虚拟机栈中引用的对象
  • 方法区中类静态属性引用的对象
  • 方法区中常量引用的对象
  • 本地方法中JNI引用的对象

Alt text

引用类型

  • 强引用(Object obj = new Object())
  • 软引用(SoftReference类)
  • 弱引用(WeakReference类)
  • 虚引用(PhantomReference类)

标记对象死亡

第一次标记:进行可达性分析后发现没有GC Roots。
第二次标记:是否需要执行finalize()方法,需要则放F-Queue队列->Finalizer线程去执行(用try-finnaly替代finalizer()方法)。

回收方法区

  • 永久代回收内容
    • 废弃容量
    • 无用的类
  • 无用的类
    • 该类所有的实例都已经被回收
    • 加载该类的ClassLoader已经被回收
    • 该类对应的java.lang.Class对象没有在任何地方被引用
  • 配置参数:-verbose: class -XX:+TraceClassLoading、-XX:+TraceClassUnLoading

垃圾收集算法

标记-清除算法

Alt text

复制算法示意图

Alt text

标记-整理算法

Alt text

分代收集算法

  • 新生代:复制算法
  • 老年代:标记-清理或者标记-整理

HotSpot的算法实现

  1. 枚举根节点
    一组称为OopMap的数据结构,在类加载完成时,HotSpot就把对象内什么偏移量上是什么类型的数据计算出来,在JTI编译过程中,也会在特定的位置记录下栈和寄存器中哪些位置是引用。

  2. 安全点
    HotSpot没有为每条指令都生成OopMap,只是在特定的位置记录了这些信息,这些位置称为安全点。
    选定标准:是否具有让程序长时间执行(指令序列复用)的特征
    确保GC发生时所有线程都”跑“到最近的安全点上再停顿下来。
    存在问题:当程序”不执行“时,无法响应JVM的中断请求?

  3. 安全区域
    是指在一段代码片段之中,引用关系不会发生变化。
    Alt text

垃圾收集器

收集算法是内存回收的方法论,垃圾收集器就是内存回收的具体实现。
Alt text

Serial收集器(单线程收集器)

最基本、发展历史最悠久的收集器。
优点:简单而高效。
缺点:停顿时间长。
Alt text

ParNew收集器(Serial多线程版本)

特征:

  • Serial收集器所有参数(收集算法、Stop The World等)
  • 除Serial收集器外,只有它能与CMS收集器配合工作
  • 新生代收集器
    Alt text

Parallel Scavenge收集器

是一个新生收集器,它是使用复制算法的收集器,又是并行的多线程收集器。
目标:达到一个可控制的吞吐量(吞吐量=运行用户代码时间/运行时间+垃圾收集时间)
配置参数:-XX: MaxGCPauseMillis、-XX: GCTimeRatio

Serial Old收集器

Serial收集器的老年代版本,单线程和“标记-整理”算法。
作用:

  • JDK1.5以及之间版本与Parallel Scavenge收集器搭配使用
  • 作为CMS收集器的后备预案

Alt text

Parallel Old收集器(JDK1.6中才开始使用)

Parallel Scavenge收集器的老年代版本,多线程和“标记-整理”算法。
Alt text

CMS收集器

是一种以获取最短回收停顿时间为目标的收集器,标记-清除算法。
特征:重视服务的响应速度。
过程:

  • 初始标记(Stop The World)
  • 并发标记(Stop The World)
  • 重新标记
  • 并发清除
    优点:并发收集、低停顿
    缺点:
  • CMS收集器对CPU资源非常敏感
  • CMS收集器无法处理浮动垃圾,可能出现失败而导致另一次Full GC的产生
    • 浮动垃圾:并发清理阶段产生的新垃圾
  • 收集结束时会有大量空间碎片产生

Alt text

G1收集器(JDK7u4达到商用)

是当今收集器技术发展的最前沿成果之一,被视为JDK1.7虚拟机的一个重要进化,是面向服务端应用的垃圾收集器。
特征:

  • 并行与并发
  • 分代收集
  • 空间整合(标志-清理、标记-整理混用)
  • 可预测的停顿

区别:

  • 将整个Java堆划分为多个大小相等的独立区域
  • 可以有计划避免在整个Java堆中进行全区域的垃圾收集。
  • 把内存“化整为零”的思路

过程:

  • 初始标记
  • 并发标记
  • 最终标记
  • 筛选回收
    Alt text

理解GC日志

  • [DefNew:Default New Generation,Serial收集器
  • [ParNew:Parallel New Generation,ParNew收集器
  • PSYoungGen:Parallel Scavenge收集器(老年代和永久代同理)

Alt text

垃圾收集器参数总结

Alt text
Alt text

内存分配与回收策略

  • 对象优先在Eden分配
  • 大对象直接进入老年代
  • 长期存活的对象将进入老年代
  • 动态对象年龄判断
  • 空间分配担保

对象优先在Eden分配

  • Minor GC:新生代的垃圾收集动作
  • Major GC|Full GC:老年代GC(比Minor GC慢10倍以上)

Alt text

大对象直接进入老年代

需要大量连续内存空间的Java对象(很长的字符串及数组)。
配置参数:-XX:PretenureSizeThreshold
Alt text

长期存活的对象将进入老年代

内存回收根据对象年龄(Age)计数器来记录对象的年龄,默认15岁。
参数配置:-XX: MaxTenuringThreshold
Alt text

动态对象年龄判断

相同年龄所有对象大小的总和大于Survivor空间的一半,直接进入老年代(不用等年龄到15)。
Alt text

空间分配担保

当老年代空间<新生代晋升空间,会根据配置参数HandlePromotionFailure来担保是否继续操作。
配置参数:HandlePromotionFailure