天天看点

《从零开始带你成为JVM实战高手》 笔记四

一、第二十二课 ParNew工作机制

1、主打多线程垃圾回收机制,主要回收新生代(回收算法和Serial一样,不过Serial是单线程的)

垃圾回收线程数量是跟CPU核数一样的,也可以使用-XX:ParallelGCThreads来设置线程数量

《从零开始带你成为JVM实战高手》 笔记四

2、指定使用ParNew垃圾回收器

-XX:+UseParNewGC,只要加入这个选项,就是使用ParNew来对新生代进行垃圾回收

3、单线程垃圾回收好还是多线程垃圾回收好

一般服务端程序都是使用多线程垃圾回收,因为他们都是多核CPU。对于一些单核的客户端程序,用单线程好一点

二、第二十三课 老年代垃圾回收时,内部做了什么

1、一般使用CMS垃圾回收器,采用标记清理算法。最大的问题会造成内存碎片

2、CMS采取垃圾回收线程和系统工作线程尽量同时执行的模式来处理,共分为4个阶段

  • 初始标记
  • 并发标记
  • 重新标记
  • 并发清理

3、初始标记

停止系统的所有线程,进入Stop the World状态,然后标记出所有GC Roots直接引用的对象,比如下面一段代码,就会标记成下图的样子。这个速度很快,因为只标记被GC Roots引用的对象

《从零开始带你成为JVM实战高手》 笔记四
《从零开始带你成为JVM实战高手》 笔记四

4、并发标记

对老年代的所有对象进行GC Roots追踪,看这些对象被谁引用了,是最耗时的。但是跟系统程序并发运行的,所以不会对系统造成影响

《从零开始带你成为JVM实战高手》 笔记四

5、重新标记

因为第二阶段里,一边标记存活对象和垃圾对象,一边系统在不停创建新对象,让老对象变成垃圾,所以第二阶段结束后,会有很多存活对象和垃圾对象是第二阶段没标记出来的,如下图

《从零开始带你成为JVM实战高手》 笔记四

再次进入Stop the World阶段,然后重新标记第二阶段里新创建的对象,还有一些已有对象可能失去引用变成垃圾的情况。这个阶段速度是很快的,因为是在第二阶段中被系统程序运行变动过的少数对象进行标记。标记完后重新恢复程序运行

6、 并发清理

这个阶段也很耗时,因为需要进行对象的清理,但是它也是跟系统程序并发运行的,所以不会影响程序运行

《从零开始带你成为JVM实战高手》 笔记四

7、思考题

问题:ParNew + CMS的GC,如何保证只做young gc

回答:修改新生代和老年代的比例,比如改成2:1,修改Eden区和Survivor区的比例,比如改成6:2:2

三、第二十四课 线上部署时,如何设置垃圾回收相关参数

1、CMS垃圾回收,会消耗CPU资源

并发标记和并发清理时,会导致有限的CPU被垃圾回收线程占用了一部分,CMS默认启动的垃圾回收线程数量是(CPU核数 + 3)/ 4(2核的话就会占用一个线程)

2、CMS垃圾回收,Concurrent Mode Failure问题

并发清理时,因为没有Stop the World,所以可能会有新的垃圾对象进入老年代,这种对象被称为浮动垃圾,它们不会在这次gc中被清除,所以CMS在老年代内存占用达到一定比例时,就自动执行Full GC,否则内存可能溢出。这个比例可以通过-XX:CMSInitiatingOccupancyFaction来设置。但如果CMS垃圾清理时,放入老年代的对象大于了可用空间,就会发生Concurrent Mode Failure,此时会自动用Serial Old来代替CMS,就是直接把程序Stop the World,回收完后再恢复

3、CMS垃圾回收,内存碎片问题

 标记清理算法会导致内存碎片问题。为了解决这个问题,CMS有一个参数 -XX:+UseCMSCompactAtFullCollection(默认开启),在Full GC后再次进行Stop the World,把存活对象挪到一起。还有一个参数是 -XX:CMSFullGCsBeforeCompaction,执行多少次Full GC后再执行一次碎片整理工作,默认是0

4、触发Full GC的几个时机

  •  老年代内存小于新生代全部内存大小且未开启空间担保参数
  • 老年代可用内存小于历次新生代GC后进入老年代的平均对象大小
  • 新生代Minor GC后存活对象大于Survivor,或同龄对象大于Survivor的50%,会进入老年代,此时如果老年代内存不足
  • -XX:CMSInitiatingOccupancyFaction参数(二十四课新增的)

四、第二十五课 案例分析,新生代JVM参数设置

《从零开始带你成为JVM实战高手》 笔记四

 设置堆内存3072M,新生代2048M,每个虚拟机栈1M,方法区256M,Eden:Survivor=8:1:1,对象年龄大于5岁进入老年代,对象大于1M进入老年代,使用ParNEW、CMS垃圾回收器

五、第二十六课 案例分析,老年代JVM参数设置

《从零开始带你成为JVM实战高手》 笔记四