深入理解 Java 虚拟机之垃圾回收
对象是否存活(何时需要被回收)的判定
引用计数算法
给对象分配一个计数器,当有一个地方引用该对象时,计数器值+1,当引用失效时-1.当值为0时表示该对象不再被使用,进行回收。
优点:实现简单、效率较高
缺点:难以解决循环引用问题
可达性分析算法
- 通过一系列称为
GC Roots
的对象为起始点往下搜索,经过的路径称为引用链Reference Chain
,当没有任何引用链相连时,认为此对象不可达,进行回收。 GC Roots
对象包含以下几种:- 虚拟机栈(栈帧中的本地变量表)中引用的对象
- 方法区中静态属性引用的对象
- 方法区中常量引用的对象
- Native方法引用的对象
垃圾回收算法
标记-清除算法(Mark-Sweep)- 用于老年代
- 分为标记-清除两步。缺点:效率不高;容易产生内存碎片
复制算法(Copying)- 一般在新生代中使用
标记-整理算法(Mark-Compact)- 用于老年代
垃圾回收器
Serial 收集器
- 单线程收集器,会
Stop The World
(暂停其他所有的工作线程造成系统停顿)-新生代收集器
Serial Old 收集器
- Serial 收集器的老年代版本
ParNew 收集器
- Serial 收集器的多线程版本 -新生代收集器
ParNew Scavenge 收集器
- 新生代收集器,更关注于吞吐量
Parallel Old 收集器
- ParNew Scavenge 收集器的老年代版本
CMS 收集器 (Concurrent Mark Sweep)
- 目标是保证垃圾回收时的停顿时间最短,整体分为四个步骤:
- 初始标记
- 并发标记
- 重新标记
- 并发清除
缺点:
- 对CPU资源较敏感(在并发阶段,由于占用部分CPU资源,会导致应用程序响应速度变慢、吞吐量下降)
- 无法处理浮动垃圾(指在并行清理阶段用户线程执行过程中产生的新的垃圾,CMS 收集器无法在本次 GC 中处理掉只能留到下一次 GC )
- 易产生内存碎片
G1 收集器
- 并行与并发
- 分代收集
- 空间整合
- 可预测的停顿
内存分配策略
-
对象优先在新生代的 Eden 区分配
-
大对象直接进入老年代
-
长期存活的对象进入老年代
每个对象有对应的年龄计数器。如果在Eden 出生,经过第一次Minor GC后仍然存活,移动到Survivor区,年龄会设为1,此后每在到 Survivor 区经过一次 Minor GC 后年龄会+1,当增加到(默认15)时,会被移动到老年代。