JVM GC算法 CMS 详解(转)

2023-11-05

前言

CMS,全称Concurrent Low Pause Collector,是jdk1.4后期版本开始引入的新gc算法,在jdk5和jdk6中得到了进一步改进,它的主要适合场景是对响应时间的重要性需求 大于对吞吐量的要求,能够承受垃圾回收线程和应用线程共享处理器资源,并且应用中存在比较多的长生命周期的对象的应用。CMS是用于对tenured generation的回收,也就是年老代的回收,目标是尽量减少应用的暂停时间,减少full gc发生的几率,利用和应用程序线程并发的垃圾回收线程来标记清除年老代。在我们的应用中,因为有缓存的存在,并且对于响应时间也有比较高的要求,因此希 望能尝试使用CMS来替代默认的server型JVM使用的并行收集器,以便获得更短的垃圾回收的暂停时间,提高程序的响应性。

 

CMS收集周期


CMS并非没有暂停,而是用两次短暂停来替代串行标记整理算法的长暂停,它的收集周期是这样:
初始标记(CMS-initial-mark) -> 并发标记(CMS-concurrent-mark) -> 重新标记(CMS-remark) -> 并发清除(CMS-concurrent-sweep) ->并发重设状态等待下次CMS的触发(CMS-concurrent-reset)。
其中的1,3两个步骤需要暂停所有的应用程序线程的。第一次暂停从root对象开始标记存活的对象,这个阶段称为初始标记;第二次暂停是在并发标记之后, 暂停所有应用程序线程,重新标记并发标记阶段遗漏的对象(在并发标记阶段结束后对象状态的更新导致)。第一次暂停会比较短,第二次暂停通常会比较长,并且 remark这个阶段可以并行标记。

而并发标记、并发清除、并发重设阶段的所谓并发,是指一个或者多个垃圾回收线程和应用程序线程并发地运行,垃圾回收线程不会暂停应用程序的执行,如果你有多于一个处理器,那么并发收集线程将与应用线程在不同的处理器上运行,显然,这样的开销就是会降低应用的吞吐量。Remark阶段的并行,是指暂停了所有应用程序后,启动一定数目的垃圾回收进程进行并行标记,此时的应用线程是暂停的。

CMS的young generation的回收采用的仍然是并行复制收集器,这个跟Paralle gc算法是一致的。

 

参数介绍

1、启用CMS:-XX:+UseConcMarkSweepGC。
2。CMS默认启动的回收线程数目是 (ParallelGCThreads + 3)/4) ,如果你需要明确设定,可以通过-XX:ParallelCMSThreads=20来设定,其中ParallelGCThreads是年轻代的并行收集线程数
3、CMS是不会整理堆碎片的,因此为了防止堆碎片引起full gc,通过会开启CMS阶段进行合并碎片选项:-XX:+UseCMSCompactAtFullCollection,开启这个选项一定程度上会影响性能,阿宝的blog里说也许可以通过配置适当的CMSFullGCsBeforeCompaction来调整性能,未实践。
4.为了减少第二次暂停的时间,开启并行remark: -XX:+CMSParallelRemarkEnabled。如果remark还是过长的话,可以开启-XX:+CMSScavengeBeforeRemark选项,强制remark之前开始一次minor gc,减少remark的暂停时间,但是在remark之后也将立即开始又一次minor gc。

5.为了避免Perm区满引起的full gc,建议开启CMS回收Perm区选项:
+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled

6.默认CMS是在tenured generation沾满68%的时候开始进行CMS收集,如果你的年老代增长不是那么快,并且希望降低CMS次数的话,可以适当调高此值:
-XX:CMSInitiatingOccupancyFraction=80

这里修改成80%沾满的时候才开始CMS回收。

7.年轻代的并行收集线程数默认是(cpu <= 8) ? cpu : 3 + ((cpu * 5) / 8),如果你希望降低这个线程数,可以通过-XX:ParallelGCThreads= N 来调整。

8.进入重点,在初步设置了一些参数后,例如:

-server -Xms1536m -Xmx1536m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:PermSize=64m 
-XX:MaxPermSize=64m -XX:-UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection 
-XX:CMSInitiatingOccupancyFraction=80 -XX:+CMSParallelRemarkEnabled 
-XX:SoftRefLRUPolicyMSPerMB=0 


需要在生产环境或者压测环境中测量这些参数下系统的表现,这时候需要打开GC日志查看具体的信息,因此加上参数:

-verbose:gc -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:/home/test/logs/gc.log


在运行相当长一段时间内查看CMS的表现情况,CMS的日志输出类似这样:

4391.322: [GC [1 CMS-initial-mark: 655374K(1310720K)] 662197K(1546688K), 0.0303050 secs] [Times: user=0.02 sys=0.02, real=0.03 secs] 
4391.352: [CMS-concurrent-mark-start] 
4391.779: [CMS-concurrent-mark: 0.427/0.427 secs] [Times: user=1.24 sys=0.31, real=0.42 secs] 
4391.779: [CMS-concurrent-preclean-start] 
4391.821: [CMS-concurrent-preclean: 0.040/0.042 secs] [Times: user=0.13 sys=0.03, real=0.05 secs] 
4391.821: [CMS-concurrent-abortable-preclean-start] 
4392.511: [CMS-concurrent-abortable-preclean: 0.349/0.690 secs] [Times: user=2.02 sys=0.51, real=0.69 secs] 
4392.516: [GC[YG occupancy: 111001 K (235968 K)]4392.516: [Rescan (parallel) , 0.0309960 secs]4392.547: [weak refs processing, 0.0417710 secs] [1 CMS-remark: 655734K(1310720K)] 766736K(1546688K), 0.0932010 secs] [Times: user=0.17 sys=0.00, real=0.09 secs] 
4392.609: [CMS-concurrent-sweep-start] 
4394.310: [CMS-concurrent-sweep: 1.595/1.701 secs] [Times: user=4.78 sys=1.05, real=1.70 secs] 
4394.310: [CMS-concurrent-reset-start] 
4394.364: [CMS-concurrent-reset: 0.054/0.054 secs] [Times: user=0.14 sys=0.06, real=0.06 secs] 

 

其中可以看到CMS-initial-mark阶段暂停了0.0303050秒,而CMS-remark阶段暂停了0.0932010秒,因此两次暂停的总共时间是0.123506秒,也就是123毫秒左右。两次短暂停的时间之和在200以下可以称为正常现象。

但是你很可能遇到两种fail引起full gc:Prommotion failed和Concurrent mode failed。

Prommotion failed的日志输出大概是这样:

[ParNew (promotion failed): 320138K->320138K(353920K), 0.2365970 secs]42576.951: [CMS: 1139969K->1120688K( 
166784K), 9.2214860 secs] 1458785K->1120688K(2520704K), 9.4584090 secs] 


这个问题的产生是由于救助空间不够,从而向年老代转移对象,年老代没有足够的空间来容纳这些对象,导致一次full gc的产生。解决这个问题的办法有两种完全相反的倾向:增大救助空间、增大年老代或者去掉救助空间。 增大救助空间就是调整-XX:SurvivorRatio参数,这个参数是Eden区和Survivor区的大小比值,默认是32,也就是说Eden区是 Survivor区的32倍大小,要注意Survivo是有两个区的,因此Surivivor其实占整个young genertation的1/34。调小这个参数将增大survivor区,让对象尽量在survitor区呆长一点,减少进入年老代的对象。去掉救助空 间的想法是让大部分不能马上回收的数据尽快进入年老代,加快年老代的回收频率,减少年老代暴涨的可能性,这个是通过将-XX:SurvivorRatio 设置成比较大的值(比如65536)来做到。在我们的应用中,将young generation设置成256M,这个值相对来说比较大了,而救助空间设置成默认大小(1/34),从压测情况来看,没有出现prommotion failed的现象,年轻代比较大,从GC日志来看,minor gc的时间也在5-20毫秒内,还可以接受,因此暂不调整。

Concurrent mode failed的产生是由于CMS回收年老代的速度太慢,导致年老代在CMS完成前就被沾满,引起full gc,避免这个现象的产生就是调小-XX:CMSInitiatingOccupancyFraction参数的值,让CMS更早更频繁的触发,降低年老代被沾满的可能。我们的应用暂时负载比较低,在生产环境上年老代的增长非常缓慢,因此暂时设置此参数为80。在压测环境下,这个参数的表现还可以,没有出现过Concurrent mode failed。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JVM GC算法 CMS 详解(转) 的相关文章

  • 如何从Firebase Firestore实时更新文档中获取修改后的字段或数据? [复制]

    这个问题在这里已经有答案了 我有多个文档 我的问题是我无法获取修改的特定数据 我正在获取完整的文档 db collection employees whereEqualTo OID OID addSnapshotListener new E
  • 如何使用Spring WebClient进行同步调用?

    Spring Framework in 休息模板 https docs spring io spring framework docs current javadoc api org springframework web client R
  • 使用 JDBC 获取 Oracle 11g 的最后插入 ID

    我是使用 Oracle 的新手 所以我将放弃之前已经回答过的内容这个问题 https stackoverflow com questions 3131064 get id of last inserted record in oracle
  • Java 7 默认语言环境

    我刚刚安装了 jre7 我很惊讶地发现我的默认区域设置现在是 en US 对于jre6 它是de CH 与jre7有什么不同 默认区域设置不再是操作系统之一吗 顺便说一句 我使用的是Windows7 谢谢你的回答 编辑 我已经看到了语言环境
  • Android 中的列表(特别是 RecyclerView 和 CardView)如何工作

    请原谅我问这个问题 但我是 Android 开发新手 尽管我正在尝试了解developer android com 网站上的基础知识 但大多数示例 即使他们说它们是为 Android Studio 构建的 尚未设置为使用 Gradle 因此
  • 如何使用 JAVA 代码以编程方式捕获线程转储?

    我想通过 java 代码生成线程转储 我尝试使用 ThreadMXBean 为此 但我没有以正确的格式获得线程转储 因为我们正在使用jstack命令 请任何人提供一些帮助 他们是否有其他方式获取线程转储 使用任何其他 API 我想要的线程转
  • (Java) App Engine 中的静态文件无法访问

    The 示例文档 http code google com appengine docs java gettingstarted staticfiles html表示您只需将文件放在 war 或子目录 中 并且应该可以从主机访问它们 只要它
  • Logback:SizeAndTimeBasedRollingPolicy 不遵守totalSizeCap

    我正在尝试以一种方式管理我的日志记录 一旦达到总累积大小限制或达到最大历史记录限制 我最旧的存档日志文件就会被删除 当使用SizeAndTimeBasedRollingPolicy在 Logback 1 1 7 中 滚动文件追加器将继续创建
  • 您建议使用哪种压缩(GZIP 是最流行的)servlet 过滤器?

    我正在寻找一个用于大容量网络应用程序的 GZIP servlet 过滤器 我不想使用容器特定的选项 要求 能够压缩响应负载 XML Faster 已在大批量应用的生产中得到验证 应适当设置适当内容编码 跨容器移植 可选择解压缩请求 谢谢 我
  • tomcat 7.0.50 java websocket 实现给出 404 错误

    我正在尝试使用 Java Websocket API 1 0 JSR 356 中指定的带注释端点在 tomcat 7 0 50 上实现 websocket 以下是我如何对其进行编码的简要步骤 1 使用 ServerEndpoint注解编写w
  • 为自定义驱动程序创建 GraphicsDevice

    我正在开发一个在嵌入式系统中使用 Java 的项目 我有用于屏幕和触摸输入的驱动程序 以及用于文本输入的虚拟键盘 我的屏幕驱动程序有一个Graphics2D您可以绘制的对象和repaint Rectangle 更新方法 类似地 触摸驱动器能
  • Java中的断点和逐步调试?

    抱歉我的问题名称很奇怪 我不知道如何寻找这个 因为我不知道这些东西是如何称呼的 Visual Studio 中至少有一个功能 您可以单击代码左侧并设置一个大红点的起点 然后运行程序 您可以通过按 f8 或 f5 实际上是不同的 f 来跟踪步
  • 当 minifyEnabled 为 true 时 Android 应用程序崩溃

    我正在使用多模块应用程序 并且该应用程序崩溃时minifyEnabled true in the installed模块的build gradle 以下是从游戏控制台检索到的反混淆堆栈跟踪 FATAL EXCEPTION Controlle
  • 如何通过 Android 按钮单击运行单独的应用程序

    我尝试在 Android 应用程序中添加两个按钮 以从单独的两个应用程序订单系统和库存系统中选择一个应用程序 如图所示 我已将这两个应用程序实现为两个单独的 Android 项目 当我尝试运行此应用程序时 它会出现直到正确选择窗口 但是当按
  • 无法在 Java/Apache HttpClient 中处理带有垂直/管道栏的 url

    例如 如果我想处理这个网址 post new HttpPost http testurl com lists lprocess action LoadList 401814 1 Java Apache 不允许我这么做 因为它说竖线 是非法的
  • Lombok @Builder 不创建不可变对象?

    在很多网站上 我看到 lombok Builder 可以用来创建不可变的对象 https www baeldung com lombok builder singular https www baeldung com lombok buil
  • 如何处理 StaleElementReferenceException

    我正在为鼠标悬停工作 我想通过使用 for 循环单击每个链接来测试所有链接的工作条件 在我的程序中 迭代进行一次 而对于下一次迭代 它不起作用并显示 StaleElementReferenceException 如果需要 请修改代码 pub
  • 替换文件中的字符串

    我正在寻找一种方法来替换文件中的字符串而不将整个文件读入内存 通常我会使用 Reader 和 Writer 即如下所示 public static void replace String oldstring String newstring
  • 使用 Java https 上传到 Imgur v3 错误

    我目前正在尝试使用他们当前的 API v3 上传到 imgur 但是我不断收到错误 错误 javax net ssl SSLException 证书中的主机名不匹配 api imgur com imgur com OR imgur com
  • 何时在 hibernate 中使用 DiscriminatorValue 注解

    在 hibernate 中使用 DiscriminatorValue 注释的最佳场景是什么以及何时 这两个链接最能帮助我理解继承概念 http docs oracle com javaee 6 tutorial doc bnbqn html

随机推荐

  • mfc 窗口初始化以及销毁过程

    1 模式对话框的创建过程 1 DoModal 重载函数 重载DoModal 成员函数 2 PreSubclassWindow 重载函数 允许首先子分类一个窗口 3 OnCreate 消息响应函数 响应WM CREATE消息 发送此消息以告诉
  • 机器学习实战 决策树(附数据集)

    运行环境 Anaconda Jupyter Notebook Python版本为 3 6 6 数据集 lense txt 提取码 9wsp 1 决策树 决策树也是最经常使用的数据挖掘算法 长方形代表判断模块 decision block 椭
  • 网络安全实验室4.注入关

    4 注入关 1 最简单的SQL注入 url http lab1 xseclab com sqli2 3265b4852c13383560327d1c31550b60 index php 查看源代码 登录名为admin 最简单的SQL注入 登
  • Could not autowire. No beans of 'OrderService' type found. less... (Ctrl+F1) Inspection info:Checks

    解决方法 步骤如下 把最后一个 去掉 点击ok就好了 当然还有一点就是 sevice类的前面加上 service注解
  • BRAM资源不够用?不怕!这里有FPGA BRAM省资源小秘招!

    FPGA的BRAM和LUT等资源都是有限的 在FPGA开发过程中 可能经常遇到BRAM或者LUT资源不够用的情况 一般建议BRAM和LUT资源的消耗不要超过80 当然高端一点的FPGA芯片也可以放宽到90 超过这个限制 可能就会出现时序违例
  • wifi中断攻击

    前言 wifi攻击包括wifi中断攻击 wifi密码爆破 wifi钓鱼等 本文章持续更新以上内容 先以wifi中断攻击为始 硬件为ESP8266 还买了一个无线网卡用作后续wifi密码爆破 网上某宝十几块钱就能玩 我买的是带Micro接口
  • Git的简述

    Git 文章目录 Git Git概述 版本控制工具 集中式管理控制工具 分步式管理控制工具 控制机制 Git和代码托管中心 安装Git软件 Git常用命令 Git概述 Git是一个免费的 开源的分步式版本控制系统 可以快速的处理从小型到大型
  • 输入一个url会发生什么事情?

    输入一个url会发生什么事情 1 输入解析 1 1 如果输入的是非url结构的字符串 则会使用默认浏览器的搜多引擎搜索这个字符串 1 2如果输入是url结构的字符串 url将通过进程建通信发送给网络进程 网络进程会进行DNS解析得到对应的I
  • 数据库基础 (关系数据库)

    14 34 属性 表的列 域 属性的范围 笛卡尔积 所有集合所有数X一遍 目或度 关系表属性的数量 候选码 唯一属性标识 主码 主键 外码 外键 主属性 候选码里的都叫主属性 全码 所有属性都是候选码 称为全码 关系的三种形式 基本关系 基
  • 国标GB28181视频监控平台EasyGBS视频无法播放,抓包返回ICMP是什么原因?

    国标GB28181视频平台EasyGBS是基于国标GB T28181协议的行业内安防视频流媒体能力平台 可实现的视频功能包括 实时监控直播 录像 检索与回看 语音对讲 云存储 告警 平台级联等功能 国标GB28181视频监控平台部署简单 可
  • 大数据手册(Spark)--Spark基础知识(PySpark版)

    文章目录 Spark 初始化 弹性分布式数据集 RDD DataFrame Spark安装配置 Spark基本概念 Spark基础知识 PySpark版 Spark机器学习 PySpark版 Spark流数据处理 PySpark版 Spar
  • Python-netfilterqueue(白帽)[netfilterqueue怎么安装在kali中?][iptables怎么用]

    一 环境安装 前要 使用python3 6以上版本安装netfilterqueue会出现报错无法安装 1 安装python3 6 前提 本机已有python3 9 在此前提下安装python3 6 问题 中间有什么报错无法进行 一般是小问题
  • C语言自动抓取淘宝商品详情网页数据,实现轻松高效爬虫

    你是否曾经遇到过需要大量获取网页上的数据 但手动复制粘贴又太过费时费力 那么这篇文章就是为你而写 今天我们将会详细讨论如何使用C语言实现自动抓取网页上的数据 本文将会从以下8个方面进行逐步分析讨论 1 HTTP协议的基本原理 在开始之前 我
  • Java 自动单元测试生成框架

    推广博客 Java 自动单元测试生成框架
  • STC15单片机自带的AD功能的使用

    一 什么是ADC DAC ADC Analog to Digital Converter的缩写 意思是模 数转换器 实现把模拟信号转变为数字量的设备称为模 数 A D 转换器 简称ADC 实现把数字量转变为模拟量的设备称为数 模 D A 转
  • PHP 登录注册附带邮箱手机号验证

    原创 请勿转载 PHP 登录注册页面 前言 一 配置数据库文件 二 登录注册代码段 1 登录 2 注册 3 主页 4 注销 总结 前言 php简单的登录页面与注册页面 有邮箱手机号验证 源码在github上 https github com
  • 双亲委派机制

    JVM双亲委派机制 JVM预定义的三种类型类加载器 定义 类加载器 ClassLoader 是Java语言的一项创新 也是Java流行的一个重要原因 在类加载的第一阶段 加载 过程中 需要通过一个类的全限定名来获取定义此类的二进制字节流 完
  • 关于SQL注入报错:Illegal mix of collations for operation ‘UNION‘原因剖析与验证

    关于SQL注入报错 Illegal mix of collations for operation UNION 原因剖析与验证 今天练习了一下DVWA的SQL注入模块 使用了union注入时报错如下 Illegal mix of colla
  • 解决“vue-router子路由默认视图不显示”问题

    今天在看Vue学习视频 老师讲解vue router多级路由的使用 在写完视频里的例子后 自己测试发现一个小问题 当时视频里没有提及 我是用name实现的路由之间的切换 其中一个有子路由 发现子路由的默认显示没有了 第一次默认有 第二次点击
  • JVM GC算法 CMS 详解(转)

    前言 CMS 全称Concurrent Low Pause Collector 是jdk1 4后期版本开始引入的新gc算法 在jdk5和jdk6中得到了进一步改进 它的主要适合场景是对响应时间的重要性需求 大于对吞吐量的要求 能够承受垃圾回