JVM垃圾回收

138 阅读5分钟

jvm内存模型

jvm model.png

程序计数器

主要是用来记录正在执行的虚拟机字节码指令的地址

Java虚拟栈

每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息,每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机中入栈到出栈的过程。

本地方法栈

本地方法栈的作用类似,本地方法栈只不过为虚拟机使用到的Native方法服务

Java堆

此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。

方法区

用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码的数据。

判断对象是否存活

引用计数法

给对象中添加一个引用计数器,每当又一个地方引用它时,计数器值加1;当引用失效时,计数器值就减1;任何时刻计数器伟0的对象时不可能再被使用的。Java虚拟机中没有采用引用计数器算法管理内存,其中最重要的原因的是它很难解决对象之间相互循环引用的问题。

可达行分析算法 GC Roots

目前主流的商用程序语言都是通过可达性分析来判定对象是否存活的。这个算法的基本思想就是通过一系列的称为“GC Roots”的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots没有任何引用链相连时,则证明此对象是不可用的。

在Java语言中,可作为GC Roots的对象包含如下:

  • 虚拟机栈(栈帧中的本地变量表)中引用的对象;
  • 方法区中类静态属性引用的对象;
  • 方法区中常量引用的对象;
  • 本地方法栈JNI(即一般说的Native方法)引用的对象

GC Root set.png

生存还是死亡

即使在可达性分析算法中不可达的对象,也并非是“非死不可”的,这时候它们暂时处于缓刑阶段,要真正宣告一个对象死亡,至少要经历两次标记过程:如果对象在进行可达性分析后发现没有与GC Roots相连接的引用链,那它将会被第一次标记并且进行一次筛选,筛选的条件是此对象是都有必要执行finalize()方法。当对象没有覆盖finalize()方法,或者finalize()方法已经被虚拟机调用过,虚拟机将这两种情况视为“没有必要执行”。

如果该对象被判定为有必要执行finalize()方法,那么这个对象将会放置一个叫做F-Queue的队列之中,并在稍后由一个由虚拟机自动建立的、低优先级的Finalizer线程区执行它。

回收方法区

垃圾收集方法

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

标记-算法分为“标记”和“清楚”两个阶段:首先标记除所有需要回收的对象,在标记完成后统一回收所有被标记的对象; 该算法的不足点:

  • 效率问题,标记和清楚两个过程的效率都不高;
  • 空间问题,标记清楚之后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序过程需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾收集动作。

mark-sweep.png

复制算法(Copying)

为了解决下效率问题,出现了复制算法; 复制算法回收过程时将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活这的对象复制到另外一块上面,然后再把已使用过的内存空间一次清理掉。这样使得每次都时对整个半区进行内存回收,内存分配时也就不用考虑内存碎片等复杂情况,只有移动堆顶指针,按顺序分配内存即可,实现简单,运行高校。只是这种算法的代价将内存缩小为了原来的一半,未免太高了一点。

copying.png

标记-整理算法(Mark-Compact)

标记过程与标记-清除算法一样,但后续步骤不是直接可回收对象进行清理,而是让所有存活的对象都向一端移动,然后直接清理掉端边界以外的内存。

mark-compact.png

分代垃圾回收算法

新生代采用复制算法,老年代采用“标记-清理”或者“标记-整理”算法进行回收

hotSpot的算法实现

枚举根节点

安全点

安全区域

垃圾收集器

collector.png

收集器工作原理优点缺点适用区域参数设置
Serial单线程、复制算法对新生代进行垃圾回收单线程新生代---
ParNewSerial的多线程版本,复制算法多线程单CPU情况下无法做到比Serial好新生代--
Parallel Scavenge并行的多线程收集器,复制算法多线程、并行新生代---
Serial old单线程、标记-整理算法对老年代进行垃圾回收单线程老年代---
Parallel oldParallel Scavenge的老年代版本,采用标记-整理多线程、并行老年代---
Cms基于标记-清除算法 1. 初始标记 2. 并发标记 3. 重新标记 4. 并发清除回收停顿时间短对CPU敏感,无法清浮动垃圾,会产生大量空间碎片老年代---
G1整体看是基于标记-整理,局部看是基于复制算法 1. 初始标记;2. 并发标记;3. 最终标记;4. 筛选回收并行和并发;分代收集;空间整合;可预测的停顿新生代和老年代---