引言:
之前的文章已经提过,java对象实例是存放在堆上的,至于是在伊甸区、存活区还是老年区,这些都是从对象回收(GC)角度来进行的逻辑划分。所以我们先说对象的回收(GC),然后再依据GC的策略来说明新的对象具体在哪个区生成。
GC(Garbage Collection):
垃圾回收,指的就是jvm占用内存的回收。那么需要回答3个问题:
- 哪些内存需要回收?——>可达性分析算法。
- 什么时候回收?——>简单的来说,伊甸区的空间不足发生新生代GC(Minor GC),老年代空间不足的时候发生老年代GC(Major GC / Full GC)
- 如何回收?——>通过垃圾回收器,jdk8默认的是UseParallelGC(PS scavenge + Serial Old),还有UseConMarkSweepGC(ParNew + CMS + Serial Old),以及UseG1GC(G1)。
1、可达性分析算法:以一系列成为“GC Root”的对象最为起始点,当一个对象没有到达GC Roots的引用链条,就判定这个对象为可回收的。
GC Roots对象:
- 虚拟机栈(栈帧中的本地变量表)中引用的对象。
- 方法区中类静态属性引用的对象。
- 方法区中常量引用的对象。
- 本地方法栈中JNI(即Native方法)引用的对象。
2、垃圾收集算法(分代收集):
- 新生代,对象存活率较低,复制算法。
- 老年代,对象存活率较高,标记-整理算法、标记-清除算法。
3、垃圾收集器:
新生代收集器:
- Serial收集器:采用“复制”算法,暂停用户线程,单线程收集。
- ParNew收集器:采用“复制”算法,暂停所有用户线程,采用多线程并行收集。和CMS老年代收集器搭配使用。关注点:GC时用户线程的停顿时间。
- Parallel Scavenge收集器:采用“复制”算法,和ParNew收集器类似,但关注点不同。关注点:高吞吐量。
老年代收集器:
- Serial Old 收集器:采用“标记-整理”算法,暂停用户线程,单线程收集。和Parallel Scavenge收集器搭配使用。
- Parallel Old收集器:采用“标记-整理”算法,暂停用户线程,多线程并行收集。和Parallel Scavenge收集器搭配使用。
- CMS(Concurrent Mark Sweep)收集器:采用“标记-清除”算法,不暂停用户线程,多线程并发收集。与ParNew收集器搭配使用。
新一代收集器:
G1(Garbage-First)收集器:
- GC工作时为并行,GC与用户线程为并发;
- 可独立管理整个GC堆,不需要与其他GC收集器配合使用;
- 空间整合:整理上看是“标记-整理”算法实现的,从局部(两个Region之间)上看是基于“复制”算法实现的。
总结:
- ParallelScavenge关注的是高吞吐量;
- CMS关注的是低停顿时间;
- G1关注的是使用时间相对较短的停顿来达到很高的吞吐量,CMS的替代品,在超大堆上表现优异(eg:8g以上)。
4、GC发生时间:
(1)MinorGC:大多数情况下,对象在新生代Eden区分配。当Eden区没有足够空间时,进行一次minorGC。如果是大对象,直接在老年代分配。
(2)FullGC:
a.系统主动调用System.gc(),不一定立即执行;
b.老年代空间不足;
c.方法区空间不足;
d.通过Minor GC后进入老年代的平均大小大于老年代的可用内存;
e.由Eden区、From Space区向To Space区复制时,对象大小大于To Space可用内存,则把该对象转存到老年代,且老年代的可用内存小于该对象大小。
参考资料:《深入JAVA虚拟机》