JVM垃圾收集器
最近在看周志明老师的深入理解JVM,之前对JVM的学习都是一些零碎的博客文章,有的时候看的是挺摸不着头脑的,原因无他,跟书籍比起来,博客的质量参差不齐,而且是别人理解总结的东西,学起来总是知其然而不知所以然。不得不说,这本书看起来让人有一种醍醐灌顶的感觉,这篇文章也算是我学习过程中的一个读书总结。
JVM垃圾收集器
都说Java和C++之间有一堵由内存管理筑起来的高墙,墙外的人想进去,墙内的人想出来,作为一名Java开发人员,在刚刚学习Java的时候就了解到JVM,总以为是高大上够不着的东西,但是总归要学一下。
什么是Stop The World
Stop The World指的是在垃圾收集的过程中,必须暂停其他所有的用户工作线程,直到垃圾收集线程工作结束,在这一期间,用户线程处于停顿的状态的,理论上来说,Stop The World时间越短,垃圾收集器越优秀,当前的垃圾收集器还没有办法完全取消掉Stop The World,只能尽可能减少Stop The World的时间
Serial收集器
特点
- Serial收集器又叫做串行收集器,它所做的事情很简单,在垃圾收集期间,暂停掉所有的用户线程,产生Stop The World
- 面向新生代,使用复制算法,在老年代使用标记-整理算法
优点
- 简单而又高效
- 额外内存消耗较少
- 没有线程交互,单核处理器下效率高
- 不会产生内存碎片
缺点
- 单线程,利用不到多核处理器的优势,堆内存较大时Stop The World时间长
ParNew收集器
特点
ParNew收集器实际上是Serial收集器的多线程版本,相较于Serial收集器,它使用了多条线程进行垃圾回收,其他的都与Serial收集器相同。
优点
- 除了Serial收集器以外,目前只有它能够与CMS收集器配合工作。常用的是ParNew收集器负责新生代,CMS收集器负责老年代。
- 多核处理器下,相较于 Serial收集器有更高的效率
- 不会产生内存碎片
缺点
- 单核处理器效率不如Serial收集器,因为要进行线程切换嘛
Paraller Scavenge收集器
特点
- 致力于达到可控制的吞吐量
吞吐量: 处理器用于处理用户代码的时间和处理器总消耗时间的比值,简单来说,就是在确定的时间内尽可能多地执行用户代码。
三个参数:
- -XX:MaxGCPauseMillis,一个大于0的毫秒数,虚拟机内存回收花费的最大时间
- -XX:GCTimeRatio,大于0小于100的整数,垃圾收集时间占总时间的比率
- -XX:+UseAdaptiveSizePolicy,开启自适应调节策略,不需要不需要人工指定新生代的大小等细节参数
Serial Old收集器
特点
- 是Serial的老年代版本,单线程,标记整理算法
用途
- 在JDK以及以前与Parallel Scavenge收集器搭配使用
- CMS收集器发生失败之后的后备预案
Parallel Old收集器
特点
- 是Parallel Scavenges收集器的老年代版本
- 多线程并发收集,标记整理算法
CMS收集器
特点
- 以获取最短停顿时间为目标
-用于老年代,标记清除算法,并发收集
四个步骤
初始标记
仅仅标记一下GC Roots能直接关联到的对象,速度很快。需要 stop the world
并发标记
从GC Roots直接关联的对象开始遍历整个对象图的过程,耗时较长但是不需要停顿用户线,可以与用户线程并发执行
重新标记
修整并发标记期间,因为用户线程的继续运行而导致标记产生变动的标记记录,停顿时间比初始标记稍长,需要 stop the world
并发清除
清理删除掉标记阶段判断死亡的对象,不需要移动存活对象,可以与用户线程并发执行
缺点
- 默认回收线程数(CPU+3)/4,在CPU核心不足四核的环境下,对用户程序影响较大
- 无法处理浮动垃圾,有可能出现收集失败导致一次完全 stop the world的Full GC,造成长时间停顿
浮动垃圾:在并发标记和并发清除阶段,由于用户程序继续执行而产生的新的垃圾对象,只能等待下一回收时再处理 - 垃圾收集阶段用户程序继续执行,需要预留出一部分内存,无法等老年代满了在挥手,默认在92%时触发。如果收集期间预留的内存无法满足程序重新分配新对,就会出现并发失败(Concurrent Mode Failure),就只能启动后备预案,临时启动Serial Old收集器进行串行收集。
- 标记-清除算法会产生内存碎片