JVM垃圾收集与内存分配策略
内存分配与回收策略
-
对象优先在Eden区分配
-
大对象直接进入老年代:
-XX:PretenureSizeThreshold
参数,大于这个设置值的对象直接在老年代分配,这样做的目的是避免在 Eden 区及两个 Survivor 区之间发生大量的内存复制。- 长期存活的对象将进入老年代:
JVM
给每个对象定义了一个对象年龄计数器。当新生代发生一次Minor GC
后,存活下来的对象年龄 +1,当年龄超过一定值时,就将超过该值的所有对象转移到老年代中去。使用-XXMaxTenuringThreshold
设置新生代的最大年龄,只要超过该参数的新生代对象都会被转移到老年代中去。
- 长期存活的对象将进入老年代:
-
动态对象年龄判定:如果当前新生代的 Survivor 中,相同年龄所有对象大小的总和大于 Survivor 空间的一半,年龄 >= 该年龄的对象就可以直接进入老年代,无须等到
MaxTenuringThreshold
中要求的年龄。 -
空间分配担保:通过清除老年代中废弃对象来扩大老年代空闲空间,以便给新生代作担保。
可能触发
JVM
进行Full GC
的情况:
System.gc()
方法的调用- 老年代空间不足
判断对象是否存活
-
引用计数法:在对象头维护着一个 counter 计数器,对象被引用一次则计数器 +1;若引用失效则计数器 -1。当计数器为 0 时,就认为该对象无效了。弊端:难解决对象之间循环引用的问题。
-
可达性分析法:所有和
GC Roots
根对象直接或间接关联的对象都是有效对象,和GC Roots
没有关联的对象就是无效对象。GC Roots
包括:- Java 虚拟机栈(栈帧中的本地变量表)中引用的对象
- 本地方法栈中引用的对象
- 方法区中常量引用的对象
- 方法区中类静态属性引用的对象
GC Roots
并不包括堆中对象所引用的对象,这样就不会有循环引用的问题。
垃圾回收算法
分代收集理论
-
复制算法(新生代)
-
标记-清理
-
标记-整理
垃圾收集器
Serial
最早出现的垃圾收集器
单线程,在进行垃圾收集时,会暂停其他工作线程(
stop the world
)
-
ParNew
,serial
的多线程并行版,新生代收集器(与serial
一样带有空间压缩整理的能力,采用指针碰撞的分配算法来给对象分配内存); -
Serial old
-
parallel Scavenge
致力于达到一个可控制的吞吐量(吞吐量=用户线程执行时间/用户线程执行时间+垃圾收集线程执行时间)
parallel old
CMS
:老年代的收集器,(基于清除算法,采用空闲列表来给对象分配内存);
首次实现了让垃圾收集线程与用户线程(基本上)同时工作,致力于缩短回收停顿时间。
运作过程
G1
面向全堆的收集器,不需要和其他收集器配合一起工作
使用region划分内存空间,并且维护优先级列表(跟踪各个region区域回收所获得的空间大小以及回收所需时间数据)
运作过程