垃圾收集器与内存分配策略
2019-05-03 本文已影响0人
valor_wang
对象存活判定算法
- 引用计数算法
虚拟机并不是通过引用计算算法来判断对象是否存活的 - 可达性分析算法
基本思路:通过一系列的称为"GC Roots"的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链,当一个对象到GC Roots 没有任何引用链相连,则证明该不可用。
JDK 1.2 之后,引用分为强引用、软引用、弱引用、虚引用,4种。
垃圾收集算法:
- 标记-清除算法(Mark-Sweep), 最基础的收集算法。不足:效率问题,标记和清除两个过程的效率都不高;空间问题,标记清除后会产生大量不连续的内存碎片,空间碎片太多可能会导致以后在程序运行过程中需要分配较大对象时,无法找到足够的连续内存而不得不提前出发另一次垃圾收集动作。
- 复制算法(Copying), 为解决效率问题.
IBM公司专门研究,新生代中的对象98%是"朝生夕死",所以并不需要1:1的比例来划分内存空间,而是将内存分为较大的Eden(80%)空间和两块较小的Survicor(10%)空间,每次使用Eden和其中一块Survivor。当回收时,将Eden和Survivor中还存活的对象一次性复制到另一块Survivor空间上,最后清理掉Eden和刚用过的Survivor空间。
缺陷:1. 对象存活率较高时,就要进行较多的复制操作,效率会变低。2. 需要额外的空间进行分配担保。 - 标记-整理算法(Mark-Compact)
不对可回收对象进行清理,而是所有存活的对象向一端移动,然后直接清理掉端边界以外的内存。 - 分代收集算法
根据对象存活周期不同将内存划分为几块。一般是把Java堆分为新生代和老年代,这样根据各年代特点采用最适当的收集算法。
算法执行效率保证
- 枚举根节点
OopMap数据结构:类加载完,HotSpot就把对象内什么偏移量上是什么类型数据计算出来,在JIT编译过程中,也会在特定的位置记录下栈和寄存器中哪些位置是引用的。GC扫描时就可以直接得知这些信息。 - 安全点(Safepoint)
- 安全区域(Safe Region)
垃圾收集器
- Serial 单线程,简单高效,新生代中使用
- ParNew :Serial多线程版本
- Parallel Scavenge 新生代收集器
目的是达到一个可控制的吞吐量。吞吐量:CPU用于运行用户代码的时间与CPU总消耗时间的比值。=运行用户代码时间/(运行用户代码时间+垃圾收集时间) - CMS (Concurrent Mark Sweep)JDK1.5收集老年代,一种以获取最短回收停顿时间为目标。使用标记-清除算法。
缺点:
- CPU资源非常敏感
- 无法处理浮动垃圾,可能出现"Concurrent Mode Failure"失败而导致另一次Full GC的产生。
- 由于使用了标记-清除算法,收集结束时有大量空间碎片产生,提前触发一次Funll GC.
- G1(Garbage First) JDK 7u4,面向服务端应用的垃圾收集器
特点:
- 并行与并发,使用多个CPU来缩短Stop-The-World 停顿的时间,G1收集器可以通过并发方式让程序继续执行。
- 分代收集
- 空间整合 G1运作期间不会产生内存空间碎片,收集后能提供规整的可用内存。
- 可预测的停顿。
- Serial Old 老年代中使用,使用标记-整理算法。
- Parallel Old 是 Parallel Scavenge老年代版本