文档章节

JVM学习笔记之二 -- 垃圾回收器

sweeeeeet
 sweeeeeet
发布于 2016/08/14 15:00
字数 2004
阅读 14
收藏 0

    上一篇博文记录了gc的各种算法,这篇博文记录HotSpot中的几种垃圾回收器。垃圾回收器是不同虚拟机对算法思想的实现。

    这张图上面三个是新生代回收器、下面三个是老年代收集器。连线表示两者可以配合使用,例如在虚拟机中可以新生代使用Serial,老年代使用CMS。下面会介绍各种回收器的特性、原理和使用场景。收集器并没有好坏之分,只有是否适合应用的场景。

一、新生代收集器

1、Serial

    顾名思义,这个收集器是“连续”的(单个GC线程)。意味着新生代执行gc时所有正常的工作线程是挂起状态。Serial是最基础的收集器。随着虚拟机的发展出现了后面的收集器,但也有其优势。简单高效,对于单核环境,没有线程交互的开销,并且适合运行在Client模式下的虚拟机。java -client, java -server可以控制jvm模式。

2、ParNew

    ParNew其实就是Serial的多线程版本,除了使用多线程垃圾收集器之外(多个GC线程),其余行为包括控制参数、收集算法、STW、对象分配规则、手机策略都与Serial相同。ParNew是server模式虚拟机首选的收集器,因为目前只有它能与CMS配合使用。ParNew适合在多核的服务器上使用。

3、Parallel Scavenge(PS)

    字面意思是“并行清理”,如图可知PS也是新生代收集器、多线程、也使用了复制算法。PS的关注点是吞吐量自适应。这是与前面收集器不同的。

    在这里吞吐量被定义为cpu用于运行用户代码的时间与cpu总时间之比。首先我想简单说一下我对吞吐量的理解。吞吐量的定义是单位时间传输、处理的字节数或其他单位。吞吐量大不一定意味着性能好或可用率高。对于gc来说cpu的吞吐量高意味着STW的时间会更长。对于要求响应速度的系统,如果有1分钟无法提供服务,是完全不合理的。选择吞吐量小但响应速度快的,可能是更好的方案。两者的区别是,后者可能是顿卡,但可以提供服务,前者是在某段时间内无法提供服务,但其他时间正常。前面可能会得出吞吐量大性能差这个结论,其实不然,吞吐量即效率,能响应更多的请求。

    所以结论是:停顿时间越短越适合与用户交互的程序,能够提升用户体验,而高吞吐量则可以高效利用cpu时间,尽快完成运算任务,主要适合后台运算而无需交互的任务。

    PS提供了两个参数用于精确控制吞吐量:最大停顿时间-XX:MaxGCPauseMillis以及吞吐量大小-XX:GCTimeRatio。GC的停顿时间缩短是牺牲了吞吐量和新生代空间,收集300M和500M新生代,肯定是前者快,但触发的频率高,假设后者是10s收集一次,每次100ms,前者是5s收集一次,每次50ms。收集速度加快,但效率变低了。

    PS收集器还有一个参数-XX:+UseAdaptiveSizePolicy。字面意思是“使用自适应的大小”,他的作用也是如此。当参数打开,就不需要指定新生代的小小、Eden和Survivor的比例等细节参数,虚拟机会根据当前系统运行情况收集性能监控信息,动态调整参数,根绝前面两个参数定义的最大停顿时间和吞吐率提供最合适的停顿时间或最大的吞吐量。

二、老年代收集器

1、Serial Old

    单线程老年代收集器,使用标记-整理算法。可以应用在client模式下的虚拟机。如果是server模式,1.可以跟PS配合使用 2.作为CMS收集器的后备方案,在并发收集产生Concurrent Mode Failure时使用,也是两者连线的原因。

2.Parallel Old

    多线程老年代收集器,同样适用标记-整理算法。在Parallel Old出现之前,新生代的PS只能与Serial Old配合使用。尴尬的是,这种组合并不能体现出PS在吞吐量上的优势。在多核环境中其综合性能不如ParNew+CMS。Parallel Old与Parallel Scavenge的组合适合应用于注重吞吐量和cpu资源敏感的场景中。这里还需要再次说明,以上不管是单线程还是多线程都会造成STW,所有工作线程都是挂起状态。

3.CMS

    Concurrent Mark Sweep 是一种以获取最短回收时间为目标的收集器。Mark Sweep -> 标记-清除算法,整个过程分为4步

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

    初始标记和重新标记任然需要STW。初始标记仅标记GC Root直接关联的对象,速度快,单线程。并发标记进行GC Roots Tracing的过程。重新标记是为了标记并发标记期间发生变化的对象,多线程。

    由于时间最长的并发标记、并发清除都是与工作线程并行的,且其余两个过程STW的时间相比并发阶段要远远小于,所以总体上来说CMS的清除过程是与用户线程并发的。

    制约CMS的条件也有很多:

  1. 因为与用户工作线程并发,毫无疑问会降低系统的并发量。CMS默认使用(cpu数量+3)/4个线程,意味着至少25%的cpu资源是用于gc的。
  2. 由于在清理过程中还会继续产生新的“垃圾”,这些垃圾只能留到下次清理,这些垃圾成为“浮动垃圾”。因此CMS不会在老年代快用完时触发,需要留一部分空间给“浮动垃圾”。虚拟机中可以通过-XX:CMSInitiatingOccupancyFraction控制空间大小。如果参数设置过高,预留空间少,则容易出现老年代无法满足需求的情况,此时就会出现一次Concurrent Mode Failure。还记得前面说的Serial Old可以配合CMS使用吗,此时就会启动这种后备方案。这样停顿时间就很长了。
  3. CMS使用标记-清除算法,无疑会增加内存碎片。我猜测不使用标记-整理算法的原因是尽量缩短STW。如果没有足够的空间分配大对象就会提前触发一次Full GC。CMS提供了-XX:+UseCMSCompactAtFullCollection的开关参数,用于没有足够空间的情况下是否做内存碎片整理的操作。默认开启。还提供了另外一个参数-XX:CMSFullGCsBeforeCompaction,用于设置执行多少次Full GC后执行一次压缩整理操作。默认是0。这点其实很尴尬,收集操作很难做到两全,就像cap理论,保证一致性就会影响可用性,保证可用性就要牺牲一致性。

 

    说了这么多都是纸上谈兵,但在上一篇博文中也说明过了,必然会有很多理论上的知识。至于收集器是如何标记、如何清除内存、如何整理等等,也许作为一个初学者或应用系统工程师会很难接触到,作为初学者的我还没有那么深的理解。但是如果把以上只是都掌握,对于运维自己开发的系统是很有帮助的。

ps:上面又是只说了GC没说是Young GC 还是 Full GC,请按不同年代的收集器理解就好。

© 著作权归作者所有

sweeeeeet
粉丝 2
博文 19
码字总数 24105
作品 0
上海
后端工程师
私信 提问
Java强软弱虚引用Reference

Java强软弱虚引用Reference 本文目的:深入理解Reference 本文定位:学习笔记 学习过程记录,加深理解,提升文字组合表达能力。也希望能给学习Reference的同学一些灵感 源码说明 源码基于jdk...

lichuangnk
2018/06/19
54
0
一张图看懂JVM之垃圾回收算法详解

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/t4i2b10X4c22nF6A/article/details/84143047 导读 在之前的内容中,我们通过一张图的方式(图),从总体上对J...

JAVA高级架构v
2018/11/16
0
0
JVM系列第9讲:JVM垃圾回收器

前面文章中,我们介绍了 Java 虚拟机的内存结构,Java 虚拟机的垃圾回收机制,那么这篇文章我们说说具体执行垃圾回收的垃圾回收器。 总的来说,Java 虚拟机的垃圾回收器可以分为四大类别:串...

陈树义
2018/11/22
0
0
Java GC系列:Java垃圾回收详解

Java的内存分配与回收全部由JVM垃圾回收进程自动完成。与C语言不同,Java开发者不需要自己编写代码实现垃圾回收。这是Java深受大家欢迎的众多特性之一,能够帮助程序员更好地编写Java程序。 ...

满风
2015/04/10
589
0
Java finalize方法

《JAVA编程思想》: java提供finalize()方法,垃圾回收器准备释放内存的时候,会先调用finalize()。 (1).对象不一定会被回收。 (2).垃圾回收不是析构函数。 (3).垃圾回收只与内存有关。 (4)....

清风伴月
2017/10/22
46
0

没有更多内容

加载失败,请刷新页面

加载更多

db.properties

jdbc.driver=com.mysql.cj.jdbc.Driverjdbc.url=jdbc:mysql://localhost:3306/mybatis?serverTimezone=GMT%2B8&characterEncoding=utf8&useSSL=falsejdbc.username=rootjdbc.pas......

行者终成事
21分钟前
3
0
从 Storm 到 Flink,汽车之家基于 Flink 的实时 SQL 平台设计思路与实践

在 2019 年之前,之家的大部分实时业务都是运行在 Storm 之上的。Storm 作为早期主流的实时计算引擎,凭借简单的 Spout 和 Bolt 编程模型以及集群本身的稳定性,俘获了大批用户。下图是实时计...

阿里云官方博客
22分钟前
4
0
网络安全-Day04

2.1.1 什么是SQL注入 2.1.2 注入分类 2.1.3 MySQL手工注入 2.1.4 sqlmap使用 2.1.5 总结 什么是SQL注入 SQL注入漏洞原理 什么是SQL 结构化查询语言(Structured Query Language),是一种特殊目...

Jerry1101
22分钟前
3
0
docker容器内安装yum,vim等命令,以及配置ls指令

使用国内镜像 mv /etc/apt/sources.list /etc/apt/sources.list.bakecho "deb http://mirrors.163.com/debian/ jessie main non-free contrib" >> /etc/apt/sources.listecho "deb http://......

长恭
22分钟前
3
0
超详细的MySQL8.0.17版本安装教程

下载MySQL MySQL的官网地址:https://www.mysql.com/。 如下图所示: 然后点击DOWNLOADS ==> Community,选择MySQL Community Server。如图所示: 滑到页面的最下面,找到Recommended Downl...

彩色泡泡糖
26分钟前
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部