0

0

详解为任务关键型Java应用优化垃圾回收(下)

黄舟

黄舟

发布时间:2017-03-23 11:03:44

|

1347人浏览过

|

来源于php中文网

原创

为任务关键型java应用优化垃圾回收(上)

并行标记清除(CMS)回收器

CMS垃圾回收器是第一个广泛使用的低延迟回收器。虽然在Java 1.4.2中就可以使用了,但刚开始还不是很稳定。这些问题直到Java 5才得以解决。

从CMS回收器的名字就可以看出它使用并行方式:大部分回收工作由一个GC线程完成,与处理用户请求的工作线程并行执行。老年代原来单一的stop-the-world回收过程被划分为两个更短的stop-the-world暂停加上5个并行阶段。在这些并行阶段中,原来的工作线程照常运行(不会被暂停)。

使用下面的参数可以激活CMS回收器:

-XX:+UseConcMarkSweepGC

再次应用到上面的测试程序(并提高负载)可以得到以下结果:

立即学习Java免费学习笔记(深入)”;

图4 优化堆大小并使用CMS的JVM在50小时内的GC行为(-Xms1200m -Xmx1200m -XX:NewSize=400m -XX:MaxNewSize=400m -XX:SurvivorRatio=6 -XX:+UseConcMarkSweepGC))

可以看到,老年代GC的8s左右暂停已经消失了。现在,老年代回收过程只出现两次暂停(前一次的结果50小时内有5次),并且所有暂停都在1s内。

默认情况下,CMS回收器使用ParNew(GC算法)处理新生代回收。如果ParNew和CMS一起运行,它的暂停会比没有CMS时长一点,因为他们之间需要额外的协同工作。与上次的测试结果相比,可以从新生代的平均暂停时间略有上升发现这个问题。新生代暂停时间中离群值频繁出现,从这里也可以发现这个问题。离群值可以达到0.5s左右。但是这些暂停对很多应用来说已经足够短了,所以CMS/ParNew组合可以作为一个很好的低延迟优化选择。

CMS回收器的一个严重缺陷就是,当老年代空间都被占满时CMS无法启动。一旦老年代被占满了,启动CMS就太晚了;虚拟机必须使用通常的“stop-the-world”策略(在GC日志中会出现“concurrent mode failure”的记录)。为了实现低延迟目标,当老年代空间占用量达到一定门限值时,就应该启动CMS回收器,通过以下设置来实现:

-XX:CMSInitiatingOccupancyFraction=80

这表示一旦老年代空间被占用80%时,CMS回收器就会运行。对于我们的应用,使用这个值(也就是默认值)就可以。但如果把门限值设太高的话,就会产生“concurrent mode failure”,导致长时间的老年代GC暂停。反过来,如果设的太低(低于活跃空间大小),CMS可能一直并行运行,导致某个CPU核心完全用在GC上。如果一个应用的对象创建和堆使用行为变化很快,比如通过交互的方式或者计时器启动专门的任务,很难设置一个合适的门限值同时避免上述两种问题。

碎片的阴影

然而,CMS最大的一个问题是它不会整理老年代堆空间。这样会产生堆碎片,随着时间运行,会导致服务严重恶化。有两个因素会导致这种情况:紧缺的老年代空间大小,以及频繁的CMS回收。第一个因素可以通过增大老年代堆空间来改善,要大于ParallelGC回收器所需要的空间(我从1024M增加到1200M,从前几幅图可以看到)。第二个问题可以通过合适地划分各代空间来优化,前面讲过。我们可以实际看一下这样可以把老年代GC的频率降低多少。

为了证明使用CMS前合理地调整各代堆大小很重要,我们先看看如果不遵守上述的原则,在图1(几乎不对堆做优化)的基础上直接使用CMS回收器会怎么样:

图5 未优化堆大小的GC行为,以及使用CMS后内存碎片导致的性能恶化(从第14小时开始)

很明显,JVM在这样设置的负载测试下可以稳定地工作将近14个小时(在生产环境以及更小的负载条件下,这个不稳定的良性阶段可能会持续更久)。接下来,突然间会出现多次很长的GC暂停,暂停时间几乎占剩余时间的一半。不仅老年代的暂停时间会达到10s以上,而且新生代的暂停时间也会达到数秒。因为回收器为了将新生代的对象移到老年代,需要耗费很长的时间搜索老年代空间。

CMS低延迟优点的代价就是内存碎片。这个问题可以最小化,但是不会彻底消失。你永远不知道它什么时候会被触发。然而,通过合理的优化与监控可以控制它的风险。

G1(Garbage First)回收器的希望

G1回收器设计的目的就是保证低延迟的同时而没有堆碎片风险。因此,Oracle把它作为CMS的一个长期取代。G1可以避免碎片风险是因为它会整理堆空间。对于GC暂停来说,G1的目标并不是使暂停时间最小化,而是设置一个时间上限,使GC暂停尽量满足这一上限值。

在将G1回收器用于测试程序中并与上述其他经典回收器做对比之前,先总结两点关于G1的重要信息。

  • Oracle在Java 7u4中开始支持G1。为了使用G1你应该将Java 7更新到最新。Oracle的GC团队一直致力于G1的研发,在最新的Java更新中(本文编写时最新版本是7u7到7u9),G1的改进很显著。另一方面,G1无法在任何Java 6版本中使用,而且到目前更优越的Java 7不可能向后移植到Java 6中。

  • 前面关于调节各代空间大小的优化对G1来说已经淘汰了。设置各代空间大小与设置暂停目标时间相冲突会使G1回收器偏离原本的设计目标。使用G1时,可以使用“-Xms”和“-Xmx”设置整体的内存大小,也可以设置GC暂停目标时间(可选),对G1来说不用设置其他选项。与ParallelGC回收器的AdapativeSizingPolicy类似,它自适应地调整各代空间大小来满足暂停目标时间。

    Upscale
    Upscale

    AI图片放大工具

    下载

遵循这些原则后,G1回收器在默认配置下的结果如下:

图6 最小配置(-Xms1024m -Xmx1024 -XX:+UseG1GC)的JVM在G1下26小时内的GC性能

在这个例子中,我们使用了默认的GC暂停目标时间200ms。从图中可以看到,平均时间与这个目标比较吻合,最长GC暂停时间与使用CMS回收器差不多(图4)。G1明显可以很好地控制GC暂停,与平均时长相比,离群值也相当少。

另一方面,平均GC暂停时间要比CMS回收器长很多(270 vs 100ms),而且更频繁。这意味着GC累积暂停时间(也就是GC本身所占总时间)是使用CMS的4倍以上(6.96% vs 1.66%)。

与CMS一样,G1也分为GC暂停阶段和并行回收阶段(不暂停任务)。同样与CMS类似,当堆占用比达到一定门限后,它才启动并行回收阶段。从图6可以看到,1GB的可用内存到目前为止并没有完全使用。这是因为G1的默认占用比门限值要比CMS低很多。也有人指出,一般来说较小的堆空间就可以满足G1的需求。

垃圾回收器的定量比较

下面的表格总结了Oracle Java 7中4种最重要的垃圾回收器在测试中的关键性能指标。在同样的应用程序上,进行相同的负载测试,但是负载的级别不同(由第2列的垃圾创建速率体现)。

表 几种垃圾回收器的比较

所有的回收器都运行在1GB的堆空间上。传统的回收器(ParallelGC、ParNewGC和CMS)另外使用下面的堆设置:

-XX:NewSize=400m -XX:MaxNewSize=400m -XX:SurvivorRatio=6

而G1回收器没有额外的堆大小设置,并且使用默认的暂停目标时间200ms,也可以显示设置:

-XX:MaxGCPauseMillis=200

从表中可以看到,传统回收器在新生代回收上(第3列)时间差不多。对ParallelGC和ParNewGC来说是差不多的,而CMS实际上也是使用ParNewGC去回收新生代。然而,在新生代GC暂停中,将新生代存活对象移入老年代需要ParNewGC和CMS的协同。这样的协同引入额外的代价,也就导致CMS的新生代GC暂停时间要略长。

第7列是GC暂停所耗费的时间占总时间的百分比,这个值可以很好地反映GC的总时间代价。因为并行GC总时间(最后一列)以及引入的CPU占用代价可以忽略。按前文所述,优化堆大小后老年代GC次数会变得很少,这样第7列的值主要由新生代GC暂停总时间所决定。新生代暂停总时间是新生代暂停(连续)时长(第3列)与暂停次数的乘积。新生代暂停频率与新生代空间大小有关,对传统回收器来说,这个大小是相同的(400MB)。因此,对传统回收器来说,第7列的值或多或少地反映着第3列的值(负载差不多的情况)。

CMS的优点可以从第6列明显看出:它用稍长的总时间代价换来了更短(低一个量级)的老年代GC暂停。对很多真实环境的应用来说,这是一个不错的折衷。

那么,对于我们的应用,G1回收器表现怎么样呢?第6列(以及第5列)可以看出,在减少老年代GC暂停时长上,G1回收器要比CMS回收器做的好。但是从第7列也可以看到,它付出相当高的代价:同样的负载下,GC总时间代价占7%,而CMS只占1.6%。

我会在后续的文章中检查在什么条件下会导致G1产生更高的GC时间代价,同样也会分析G1与其他回收器(尤其是CMS回收器)相比的优缺点。这是一个庞大而且有价值的主题。

总结与展望

对所有的经典Java GC算法(SerialGC、ParallelGC、ParNewGC和CMS)来说,优化各代堆空间大小是很重要的,然而实际中很多应用程序并没有做足够合理的优化。导致的结果就是应用性能不够优化,以及操作退化(造成性能损失,如果没有很好地监控甚至会出现一段时间内程序暂停的情况)。

优化各代堆空间大小可以显著提高应用性能,并将GC长暂停次数减到最小。然后,消除GC长暂停需要使用低延迟回收器。CMS一直(直到现在)是首选且有效的低延迟回收器。在很多情况下,CMS就可以满足需求。通过合理的优化,它还是可以保证长期稳定,只不过存在堆碎片的风险。

作为替代,G1回收器目前(Java 7u9)是一个被支持且可用的选择,但仍有改进的余地。对很多应用来说,它的结果可以接受,但与CMS回收器相比还不是很好。其优缺点的细节值得仔细地研究

相关文章

java速学教程(入门到精通)
java速学教程(入门到精通)

java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
全国统一发票查询平台入口合集
全国统一发票查询平台入口合集

本专题整合了全国统一发票查询入口地址合集,阅读专题下面的文章了解更多详细入口。

14

2026.02.03

短剧入口地址汇总
短剧入口地址汇总

本专题整合了短剧app推荐平台,阅读专题下面的文章了解更多详细入口。

24

2026.02.03

植物大战僵尸版本入口地址汇总
植物大战僵尸版本入口地址汇总

本专题整合了植物大战僵尸版本入口地址汇总,前往文章中寻找想要的答案。

14

2026.02.03

c语言中/相关合集
c语言中/相关合集

本专题整合了c语言中/的用法、含义解释。阅读专题下面的文章了解更多详细内容。

2

2026.02.03

漫蛙漫画网页版入口与正版在线阅读 漫蛙MANWA官网访问专题
漫蛙漫画网页版入口与正版在线阅读 漫蛙MANWA官网访问专题

本专题围绕漫蛙漫画(Manwa / Manwa2)官网网页版入口进行整理,涵盖漫蛙漫画官方主页访问方式、网页版在线阅读入口、台版正版漫画浏览说明及基础使用指引,帮助用户快速进入漫蛙漫画官网,稳定在线阅读正版漫画内容,避免误入非官方页面。

12

2026.02.03

Yandex官网入口与俄罗斯搜索引擎访问指南 Yandex中文登录与网页版入口
Yandex官网入口与俄罗斯搜索引擎访问指南 Yandex中文登录与网页版入口

本专题汇总了俄罗斯知名搜索引擎 Yandex 的官网入口、免登录访问地址、中文登录方法与网页版使用指南,帮助用户稳定访问 Yandex 官网,并提供一站式入口汇总。无论是登录入口还是在线搜索,用户都能快速获取最新稳定的访问链接与使用指南。

107

2026.02.03

Java 设计模式与重构实践
Java 设计模式与重构实践

本专题专注讲解 Java 中常用的设计模式,包括单例模式、工厂模式、观察者模式、策略模式等,并结合代码重构实践,帮助学习者掌握 如何运用设计模式优化代码结构,提高代码的可读性、可维护性和扩展性。通过具体示例,展示设计模式如何解决实际开发中的复杂问题。

2

2026.02.03

C# 并发与异步编程
C# 并发与异步编程

本专题系统讲解 C# 异步编程与并发控制,重点介绍 async 和 await 关键字、Task 类、线程池管理、并发数据结构、死锁与线程安全问题。通过多个实战项目,帮助学习者掌握 如何在 C# 中编写高效的异步代码,提升应用的并发性能与响应速度。

2

2026.02.03

Python 强化学习与深度Q网络(DQN)
Python 强化学习与深度Q网络(DQN)

本专题深入讲解 Python 在强化学习(Reinforcement Learning)中的应用,重点介绍 深度Q网络(DQN) 及其实现方法,涵盖 Q-learning 算法、深度学习与神经网络的结合、环境模拟与奖励机制设计、探索与利用的平衡等。通过构建一个简单的游戏AI,帮助学习者掌握 如何使用 Python 训练智能体在动态环境中作出决策。

2

2026.02.03

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 3.2万人学习

C# 教程
C# 教程

共94课时 | 8.4万人学习

Java 教程
Java 教程

共578课时 | 56.5万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号