JAVA GC 原理详解

大多数状况下咱们对GC的了解都只是浅层含义上的,下面咱们来详细讲解下内部的一些实现原理。
讲解GC以前,咱们得先了解下JVM的内存结构,才能让咱们理解GC致使是干吗的。算法

一.JVM 内存结构

JVM内存结构由5个部分组成,分别以下数组

1. 程序计数器(Program Conuter Register)

一块较小的内存空间,它是当前线程执行字节码的行号指示器,字节码解释工做器就是经过改变这个计数器的值来选取下一条须要执行的指令。它是线程私有的内存,也是惟一一个没有OOM异常的区域。服务器

2. Java虚拟机栈区(Java Virtual Machine Stacks)

也就是一般所说的栈区,它描述的是Java方法执行的内存模型,每一个方法被执行的时候都建立一个栈帧(Stack Frame),用于存储局部变量表、操做数栈、动态连接、方法出口等。每一个方法被调用到完成,至关于一个栈帧在虚拟机栈中从入栈到出栈的过程。此区域也是线程私有的内存,可能抛出两种异常:若是线程请求的栈深度大于虚拟机容许的深度将抛出StackOverflowError;若是虚拟机栈能够动态的扩展,扩展到没法动态的申请到足够的内存时会抛出OOM异常。多线程

3. 本地方法栈(Native Method Stacks)

本地方法栈与虚拟机栈发挥的做用很是类似,区别就是虚拟机栈为虚拟机执行Java方法,本地方法栈则是为虚拟机使用到的Native方法服务。并发

4. 堆区(Heap)

全部对象实例和数组都在堆区上分配,堆区是GC主要管理的区域。堆区还能够细分为新生代、老年代,新生代还分为一个Eden区和两个Survivor区。此块内存为全部线程共享区域,当堆中没有足够内存完成实例分配时会抛出OOM异常。线程

5. 方法区(Method Area)

方法区也是全部线程共享区,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。GC在这个区域不多出现,这个区域内存回收的目标主要是对常量池的回收和类型的卸载,回收的内存比较少,因此也有称这个区域为永久代(Permanent Generation)的。当方法区没法知足内存分配时抛出OOM异常。设计


二.GC 原理

针对GC的原理机制,主要搞清楚下面三个问题。code

  1. 何时回收?
  2. 哪些须要回收?
  3. 怎么回收?

1. 何时回收?

1.对象优先分配到新生代的Eden区,当不够空间的时候进行一次Minor GC,清理频率很高。
2.Full GC发生在老年代,当不够空间的时候进行一次Full GC,伴随着也会进行一次Minor GC。
3.进行Minor GC时,会判断每次变成晋升到老年代的对象平均值是否大于老年代剩余空间,若是大于,则进行一次Full GC,若是小于就会去判断HandlePromotionFailure设置是否容许担保失败,若是容许,则进行Minor GC,不容许则改成Full GC。对象

上面提到GC主要管理的是堆区,堆区主要分为`新生代`和`老年代`
* 【新生代】分为一个Eden和两个Survivor区。新new的对象都放在这里,很快消亡。
* 【老年代】新new的大对象直接丢到这里(为了不在Eden区和两个Survivor区发生大量的内存拷贝),其他就是在新生代屡次回收没被干掉过来变成老家伙的对象了。

2. 哪些须要回收?

当调用了finalize()方法后,则须要进行清理,具体场景如上。内存

* 什么是finalize()方法?

每次进行GC以前系统都会调用一次finalize()方法,用以清理全部活动而且释放资源。

* 何时调用finalize()方法?

1.GC调用以前,例如运行System.gc();(调用System.gc()只是建议JVM去执行,是否执行还得JVM去判断)
2.程序退出时,每一个对象都会调用finalzie
3.显式调用finalize

3. 怎么回收?

JVM会根据不一样的收集器使用不一样的算法组合来达到回收的效果

### 垃圾收集算法

* mark-sweep(标记-清除)- 标记全部须要回收的对象,在标记完成后统一回收这些对象。

缺点:1.标记和清除两个过程的效率都不高。2.标记清除会产生大量不连续的内存碎片。

* copying(复制)- 主要用来回收新生代

新生代分为一个Eden区、两个Survivor区(Survivor0、Survivor1),Eden和Survivor默认8:1。回收时先把Eden存活对象复制到Survivor0区,清空Eden区,当Survivor0区满了之后,把Eden和Survivor0区的存活对象复制到Survivor1区,清空Eden区和Survivor0区,以后交换Survivor0和Survivor1区,保持Survivor1区是空的,如此往复

* mark-compact(标记-整理)

主要用来回收老年代。标记须要回收的对象,将其余存活的对象都向一端移动,而后直接清理掉端边界之外的内存。

* generational collection(分代)

目前经常使用的收集算法,区分新生代和老年代作不一样的算法收集。针对新生代,只有少许存活,选用复制算法。针对老年代,存活率高,没有额外的空间对它进行分配担保,就必须使用“标记-清理”或者“标记-整理”算法来进行回收。

--------

### 垃圾收集器

* Serial 、Serial Old 收集器 [-XX:+UseSerialGC,使用 Serial + Serial Old 组合回收]

适合单处理器系统,而且在进行垃圾回收的时候会暂停其余全部的工做线程(stop the world),对于多处理器的系统来讲是灾难

* ParNew 收集器 [-XX:UseParallelGC,使用 Parallel Scavenge + Serial Old 组合回收]

serial 收集器的多线程版本。ParNew是许多运行在Server模式下的虚拟机中首选的新生代收集器,除了Serial收集器外,只有它能与CMS收集器配合工做

* Parallel Scavenge 、Parallel Old 收集器 [-XX:GCTimeRatio,-XX:MaxGCPauseMillis]

经过两个参数GCTimeRatio和MaxGCPauseMillis,尽量缩短垃圾收集器用户线程的停顿时间,从而达到一个可控制的吞吐量。

* CMS (Concurrent Mark Sweep)收集器 [-XX:UseConcMarkSweepGC,使用 ParNew + CMS + Serial Old 组合回收]

以获取最短回收停顿时间为目标的收集器。

步骤

1.初始标记(CMS initial mark),标记GC Roots能直接关联到的对象,速度很快
2.并发标记(CMS concurrent mark),进行GC Roots Tracing
3.从新标记(CMS remark),从新标记阶段是为了修正并发标记期间因用户程序继续运做而致使变更的标记记录,比并发标记时间短
4.并发清除(CMS concurrent sweep)并行删除

缺点
1. 比较消耗CPU资源,默认启动回收线程数是(CPU数量+3)/4。
2. CMS收集器没法处理浮动垃圾(CMS清理阶段用户线程还运行着,伴随生成的新垃圾只能在下次GC再清理掉),可能出现“Concurrent Mode Failure”而致使另外一次Full GC的产生。能够经过-XX:CMSInitiatingOccupancyFraction来调节。
3. 标记-清除会致使内存碎片而致使触发Full GC(切换到Serial Old收集器收集老年代)。能够经过-XX:UseCMSCompactAtFullCollection、-XX:CMSFullGCsBeforeCompaction来调节。

* G1(Garbage-First) 收集器 [-XX:+UseG1GC]

Java堆的内存分布和其余收集器有很大不一样,它将整个Java堆划分为多个大小相等的独立区域`Region`,老年代和新生代再也不物理隔离,而是一部分`Region`的集合。G1设计初衷是为了缩短大堆(>4GB)时的停顿时间。它会跟踪各个Region的垃圾堆积价值大小,后台维护一个优先列表,每次根据容许的收集时间,优先回收价值最大的`Region`。

特色
1.并发和并行
2.分代收集
3.空间整合
4.可预测的停顿

步骤
1.初始标记(Initial Marking)
2.并发标记(Concurrent Marking)
3.最终标记(Final Marking)
4.筛选回收(Live Data Counting and Evacuation)

补充:

一、并行Parallel-XX:+UseParalleGC,追求吞吐量
多条垃圾收集线程并行工做,但此时用户线程仍然处于等待状态
二、并发ConcurrentUseConcMarkSweepGC,追求响应速度
指用户线程与垃圾收集线程同时执行(但并不必定是并行的,可能会交替执行),用户程序在继续运行,而垃圾收集程序运行于另外一个CPU上

串行处理器: Serial
--适用状况:数据量比较小(100M左右);单处理器下而且对响应时间无要求的应用。
--缺点:只能用于小型应用
并行处理器:UseParalleGC
--适用状况:“对吞吐量有高要求”,多CPU、对应用响应时间无要求的中、大型应用。举例:后台处理、科学计算。
--缺点:应用响应时间可能较长
并发处理器:UseConcMarkSweepGC--适用状况:“对响应时间有高要求”,多CPU、对应用响应时间有较高要求的中、大型应用。举例:Web服务器/应用服务器、电信交换、集成开发环境。

相关文章
相关标签/搜索