,请参阅:
《深入理解Java虚拟机-JVM高级特性与最佳实践》 周志明 著
概述
由于不同的对象适合使用不同的垃圾收集算法,所以引入“代”这个概念。不同的代有不同的分区,一般分为新生代区和老年代区。
新生代(Young Generation):适合采用复制算法(将可用内存容量划分为大小相等的两块,每次只使用其中的一块。当这一块用完之后,就将还存活的对象复制到另外一块上)进行垃圾收集,对象分布在Eden/S0/S1三个区。
老年代(Tenured/Old Generation):适合采用标记-整理算法(将存活的对象标记后都向一端移动,然后清理掉边界外地内存)进行垃圾收集
当GC只发生在young generation中,回收young generation中的对象,称为Minor GC
当GC发生在tenured generation时则称为Major GC;Full GC(清理整个堆空间—包括年轻代和永久代)。一般的,Minor GC的发生频率要比Major GC高很多。
S0/S1是大小相当的两个区域,共同组成Survivor区。空间比例:Eden:S0==8:1。设定方法:-XX:SurvivorRatio=8。
Old 老年代:每个对象有“对象年龄计数器”。对象由Eden收集到Survivor区后,年龄+1。进行新生代GC后,年龄+1。依次,当年龄>=15后进入老年代。
动态年龄:如果在Survivor中所有相同年龄对象占用了空间的一半多,大于等于上述年龄的对象直接进入老年代。
大对象(比如大的数组)直接进入老年代
Perm 永久代(Permanent Generation):用于存放不变对象,如类、方法、字符串等;Java7把驻留字符串(intentd string)放到了老年代区。Java8中移除了Hotspot的永久代区
HotSpot虚拟机几种基础经典算法及其思想
1. Serial/Serial Old收集器
- 单线程:使用1个CPU(1条收集线程)完成垃圾收集工作,且在它进行垃圾收集时,必须暂停其他所有工作线程,直至收集结束。“Stop The World”
- 最基本、最悠久的收集器。包括Serial(新生代) 和Serial Old(老年代)。Serial收集器是运行在Client模式下的虚拟机的一个GC选择。
2. ParNew收集器
在垃圾收集器的上下文语境中,并行和并发分别表示:
并行:指多条垃圾收集线程并行工作,但此时用户线程仍然处于等待状态。
并发:指用户线程与垃圾收集线程同时执行(不一定并行,可能交替执行),用户线程在继续运行,而垃圾收集程序运行于另一个CPU上。
- 多线程: ParNew收集器其实就是Serial收集器的多线程版本(多线程收集)。许多参数基本同Serial收集器。
- ParNew收集器是运行在Server模式下的虚拟机中首选的新生代收集器。
- ParNew与Serial是能与CMS收集器配合工作的唯一2个收集器
- 默认开启的收集线程数与CPU的数量相同。
3. Parallel Scavenge收集器
- 新生代收集器,使用复制算法
- 目标:达到一个可控制的吞吐量(Throughput)。这里的吞吐量=运行用户代码时间/(运行用户代码时间+垃圾收集时间)。吞吐量优先收集器
- CMS等收集器关注尽可能缩短垃圾收集时间时用户线程的停顿时间。停顿时间越短就越适合需要与用户交互的程序,良好的响应速度能提升用户体验,而高吞吐量则可以高效率利用CPU时间,主要适合在后台运算而不需要太多交互的任务。
- 2个控制吞吐量的参数:控制最大垃圾收集停顿时间:-XX:MaxGCPauseMillis ,直接设置吞吐量大小:-XX:GCTimeRatio
4. Parallel Old收集器
- 是Parallel Scavenge的年老代版本,使用多线程的标记-整理算法,在JDK1.6才开始提供
- 在JDK1.6之前,新生代使用Parallel Scavenge收集器只能搭配年老代的Serial Old收集器,只能保证新生代的吞吐量优先,无法保证整体的吞吐量
5. CMS收集器
- CMS(Concurrent Mark Sweep)收集器是一种以获取最短垃圾回收停顿时间为目标的老年代垃圾收集器。
- 集中在互联网网站或者B/S系统的服务端上,重视服务的响应速度,希望系统停顿时间最短,给用户带来较好用户体验。
- 四个步骤:初始标记、并发标记、重新标记和并发清除。
- a.初始标记:stop the world. 仅仅是标记下GC roots 能直接关联到的对象,速度很快,仍然需要暂停所有的工作线程。
- b.并发标记:进行GC Roots跟踪的过程,和用户线程一起工作,不需要暂停工作线程。
- c.重新标记:为了修正在并发标记期间,因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,仍然需要暂停所有的工作线程。
d.并发清除:清除GC Roots不可达对象,和用户线程一起工作,不需要暂停工作线程。
不足:CMS收集器对CPU资源非常敏感,其默认启动的收集线程数=(CPU数量+3)/4,在用户程序本来CPU负荷已经比较高的情况下,如果还要分出CPU资源用来运行垃圾收集器线程,会使得CPU负载加重。CMS无法处理浮动垃圾(*Floating Garbage),可能会导致Concurrent Mode Failure失败而导致另一次Full GC。CMS收集器是基于标记-清除算法,因此不可避免会产生大量不连续的内存碎片*,如果无法找到一块足够大的连续内存存放对象时,将会触发因此Full GC。
6.G1收集器
Garbage-First:当今收集器最前沿成果之一,在JDK 7u4后实现商用
特点
- 并行与并发:充分利用多CPU、多核环境
- 分代收集:同其他收集器。
- 空间整合:整体来看属于标记-整理(Mark-Compact)算法,局部来看属于复制算法。所以G1收集器在运作期间不会产生内存碎片。
- 可预测的停顿:这是G1相对于CMS的另一大优势。G1可以建立可预测的停顿时间模型。能让使用者明确指定在一个长度为M毫秒的时间片里,消耗在垃圾收集器的时间不超过N毫秒。
- Java堆内存布局:与其他收集器不同,G1收集器将整个Java堆划分为多个大小相等的独立区域(Region),这样新生代老年代不再是物理隔离得了,都属于一部分Region的集合。
- 如何建立可预测停顿时间模型?:G1首先跟踪各个Region里面的垃圾堆积的大小,在后台维护一个优先列表,每次根据允许的收集时间,优先回收价值最大的Region(Garbage First的由来)。“使用Region 划分内存空间以及有优先级的区域回收方式”。
步骤
- 初始标记(Initial Marking):
- 并发标记(Concurrent Marking):
- 最终标记(Final Marking):
- 筛选回收(Live Data and Evacuation):