一、垃圾回收器
-
垃圾回收器作用区图
下图展示了用于不同分代的收集器,如果两个收集器之间存在连线,就说明他们可以搭配使用。回收器所属的区域代表它是新生代收集器还是老年代收集器。
该图针对JDK1.7 Update14 之后的HotSpot虚拟机。
-
Serial收集器
Serial(串行)收集器是最基本、最悠久的垃圾收集器。正如其命名,这个是单线程的收集器,工作时只会使用一条GC线程去完成垃圾回收工作,更重要的是他在进行GC时会暂停其他线程(“Stop The Word”)直到它完成GC工作。
分代算法:作用于新生代,使用复制算法
优点:GC时只有一个GC线程工作,简单而高效,对处于Client模式下的虚拟机是不错的选择。
缺点:Stop The World,停顿时间长。
-
ParNew收集器
ParNew收集器其实就是Serial收集器多线程版本,除了使用多线程进行垃圾收集外,其余行为(控制参数、收集算法、回收策略等)和Serial收集器一样。
优点:GC时只有多个GC线程工作,是出于Server模式下的虚拟机的首要选择。
缺点:Stop The World,停顿时间长。
-
Parallel Scavenge收集器(JDK1.8)
Paraller Scavenge收集器类似于ParNew收集器,也是作用于新生代使用复制算法的多线程收集器。区别在于Parallel Scavenge关注点在于吞吐量( 运行用户代码时间/(CPU运行用户代码+垃圾收集时间) ),而CMS等收集器关注点是缩短GC时用户线程停顿时间。但此收集器无法与CMS搭配使用。
分代算法:作用于新生代,使用复制算法。
-
Serial Old收集器
Serial Old是Serial收集器的老年代版本,也是一个单线程收集器,使用"标记-整理"算法。
意义:主要意义在于给Client模式下的虚拟机使用。但在Server模式虚拟机下还有两大用途:一是JDK1.5以及之前版本中于Parallel Scavenge收集器搭配使用;二是作为CMS收集器的后备预案。 -
Parallel Old收集器
Parallel Old是Parallel Scavenge收集器的老年代版本,使用多线程和”标记-整理“算法,主要用于与Parallel Scavenge收集器共同使用。 -
CMS收集器
CMS(Concurrent Mark Sweep)收集器是一种以获取最短GC停顿时间为目标的收集器,适用于互联网站或B/S服务端上以减少系统停顿时间。CMS收集器是HotSpot虚拟机第一款真正意义上的并发收集器,第一次实现了垃圾收集线程与用户线程(基本上)同时工作。
CMS垃圾收集使用”标记-清除“(Mark Sweep)算法实现,整个回收过程分四个步骤:
- 初始标记(CMS intial mark):暂停其他线程,记录下直接与GC Roots连接的对象,速度很快。
- 并发标记(CMS concurrent mark):同时开启GC和用户线程,在这个阶段进行GC Roots可达性分析。由于此时用户现场也在工作,因此引用可能会变化,算法里实现了跟踪记录这些引用发生更新的地方。
- 重新标记(CMS remark):只有GC线程以多线程方式执行,修正并发标记阶段用户程序执行导致标记产生变动的那部分对象的标记记录。停顿时间比初始标记稍长,但远比并发标记短。
- 并发清除(CMS concurrent sweep):开启用户线程,同时GC线程开始清除标记区域。
缺点:
①对CPU资源敏感:GC线程并发会占用大量CPU资源,虽然不会导致用户线程停顿,但会导致用户线程变慢,因此CMS对CPU资源较敏感。
②CMS无法处理浮动垃圾:浮动垃圾指的是并发清除阶段用户线程也在执行时产生的新的无用对象。由于用户线程仍在运行,因此需要预留一部分老年代空间以存放新进来的老年代对象,而不像其他垃圾收集器一样等到老年代满了再进行垃圾收集。
③”标记-清除“算法产生的空间问题——空闲内存不连续,产生大量内存碎片
- G1收集器
G1(Gabage-First)收集器是一款面向服务器应用的垃圾收集器,HotSpot开发团队赋予它的使命是再未来可以代替CMS收集器。
G1收集器特点如下:
①并行与并发:G1能充分利用多CPU、多核环境下的硬件优势,使用多个CPU来缩短Stop-The-World停顿时间,部分其他收集需要停顿Java程序以执行GC动作,而G1收集器仍能通过并发的方式让Java程序机型执行。
②分代收集:分代概念在G1仍保留,G1不需要其他收集器配合就能管理整个GC堆。G1将Java堆划分为多个大小相等的独立区域(Region),虽然还有分代的概念,但是新生代和老年代已经不是物理隔离的了,他们都是一部分Region(无需连续)的集合。
③空间整合:整体来看G1是基于”标记-整理“算法的,局部来看是基于”复制“算法的,这两种算法都不会产生内存碎片,长时间运行的话大对象就不会因为找不到连续空闲内存空间而触发GC。
④可预测的停顿:G1除了追求低停顿外,还建立了可预测的停顿时间模型,能让使用者指定在一个长度为M毫秒的时间片段内,消耗在GC上的时间不得超过N毫秒,这几乎已经是实时Java(RSTJ)的垃圾收集器特征了。
G1收集动作分以下步骤:
①初始标记(Initial Marking):标记以下GC Roots能直接关联到的对象,耗时很短。
②并发标记(Concurrent Marking):从GC Roots开始进行可达性分析,找出存活的对象,耗时较长。
③最终标记(Final Marking):修正在并发标记期间因用户程序继续运作而导致标记产生变动的那部分标记记录,对象变化记录在线程Remembered Set Logs里面,最终标记阶段会把Remembered Set Logs的数据合并到Remembered Set中。
④筛选回收(Live Data Counting and Evacuation):根据各个Region的回收价值和成本(回收所的空间大小及回收所需时间)进行排序,根据用户期望GC停顿时间制定回收计划。
9. ZGC(JDK 11以后出现的)
- 停顿时间不超过10ms
- 停顿时间不会因堆变大而变长
- 堆大小范围可支持几G到几T
二、调优常用命令
- Jinfo:可用于查看正在运行的java程序扩展参数
- Jstat:可查看堆内存各部分的使用量及加载类的数量
- Jps:查看当前运行的Java程序及对应进程ID
- jmap:查看内存信息,可导出dump文件
- jstack:生成java虚拟机当前时刻的线程快照
三、工具
- PerfMa
用于检测Java程序性能的工具 - Java VisualVM
java自带的性能监测工具,位置在 jdk根目录/bin/jvisualvm.exe。
四、笔记目录
JVM关键总结(一)——类加载机制
JVM关键总结(二)——JVM内存结构
JVM关键总结(三)——分代与垃圾回收算法
JVM关键总结(四)——垃圾回收器及调优命令与工具
参考资料:
1.《深入理解Java虚拟机第二版》——周志明