上一篇:深夜看了张一鸣的微博,让我越想越后怕

来源:https://zhenbianshu.github.io/

背景

最近对负责的项目进行了一次性能优化,其中包括对 JVM 参数的调整,算是进行了一次简单的 JVM 调优,JVM 参数调整之后,服务的整体性能有 15% 左右的提升,还算不错。

先介绍一下项目的基本情况:

项目是一个高 QPS 压力的 web 服务,单机 QPS 一直维持在 1.5K 以上,由于旧机器的”拖累”,配置的堆大小是 8G,其中 young 区是 4G,垃圾回收器用的是 parNew + CMS。

旧状

首先是查看当前 GC 的情况,主要是使用 jstat 查看 GC 的概况,再查看 gc log,分析单次 gc 的详细状况。

使用 jstat -gcutil pid 1000 每隔一秒打印一次 gc 统计信息。

可以看到,单次 gc 平均耗时是 60ms 左右,还算可以接受,但 YGC 非常频繁,基本上每秒一次,有的时候还会一秒两次,在一秒两次的时候,服务对业务响应时长的压力就会变得很大。

接着查看 gc log,打印 gc log 需要在 JVM 启动参数里添加以下参数:

  • -XX:+PrintGCDateStamps:打印 gc 发生的时间戳。

  • -XX:+PrintTenuringDistribution:打印 gc 发生时的分代信息。

  • -XX:+PrintGCApplicationStoppedTime:打印 gc 停顿时长

  • -XX:+PrintGCApplicationConcurrentTime:打印 gc 间隔的服务运行时长

  • -XX:+PrintGCDetails:打印 gc 详情,包括 gc 前/内存等。

  • -Xloggc:../gclogs/gc.log.date:指定 gc log 的路径

看到的 gc log 形如:

单次 GC 方面并不能直接看出问题,但可以看到 gc 前有很多次 18ms 左右的停顿。

分析和调整

YGC 频繁

直接查看 gc log 并不直观,我们可以借用一些可视化工具来帮助我们分析, [gceasy](https://gceasy.io/) 是个挺不错的网站,我们把 gc log 上传上去后, gceasy 可以帮助我们生成各个维度的图表帮助分析。

查看 gceasy 生成的报告,发现我们服务的 gc 吞吐量是 95%,它指的是 JVM 运行业务代码的时长占 JVM 总运行时长的比例,这个比例确实有些低了,运行 100 分钟就有 5 分钟在执行 gc。幸好这些 GC 中绝大多数都是 YGC,单次时长可控且分布平均,这使得我们服务还能平稳运行。

解决这个问题要么是减少对象的创建,要么就增大 young 区。前者不是一时半会儿都解决的,需要查找代码里可能有问题的点,分步优化。

而后者虽然改一下配置就行,但以我们对 GC 最直观的印象来说,增大 young 区,YGC 的时长也会迅速增大。

其实这点不必太过担心,我们知道 YGC 的耗时是由 GC 标记 + GC 复制 组成的,相对于 GC 复制,GC 标记是非常快的。而 young 区内大多数对象的生命周期都非常短,如果将 young 区增大一倍,GC 标记的时长会提升一倍,但到 GC 发生时被标记的对象大部分已经死亡, GC 复制的时长肯定不会提升一倍,所以我们可以放心增大 young 区大小。

由于低内存旧机器都被换掉了,我把堆大小调整到了 12G,young 区保留为 8G。

分代调整

除了 GC 太频繁之外,GC 后各分代的平均大小也需要调整。

我们知道 GC 的提升机制,每次 GC 后,JVM 存活代数大于 MaxTenuringThreshold 的对象提升到老年代。当然,JVM 还有动态年龄计算的规则:按照年龄从小到大对其所占用的大小进行累积,当累积的某个年龄大小超过了 survivor 区的一半时,取这个年龄和 MaxTenuringThreshold 中更小的一个值,作为新的晋升年龄阈值,但看各代总的内存大小,是达不到 survivor 区的一半的。

所以这十五个分代内的对象会一直在两个 survivor 区之间来回复制,再观察各分代的平均大小,可以看到,四代以上的对象已经有一半都会保留到老年区了,所以可以将这些对象直接提升到老年代,以减少对象在两个 survivor 区之间复制的性能开销。

所以我把 MaxTenuringThreshold 的值调整为 4,将存活超过四代的对象直接提升到老年代。

偏向锁停顿

还有一个问题是 gc log 里有很多 18ms 左右的停顿,有时候连续有十多条,虽然每次停顿时长不长,但连续多次累积的时间也非常可观。

1.8 之后 JVM 对锁进行了优化,添加了偏向锁的概念,避免了很多不必要的加锁操作,但偏向锁一旦遇到锁竞争,取消锁需要进入 safe point,导致 STW。

解决方式很简单,JVM 启动参数里添加 -XX:-UseBiasedLocking 即可。另外,关注公众号互联网架构师,在后台回复:2T,可以获取我整理的 JVM 系列面试题和答案,非常齐全。

结果

调整完 JVM 参数后先是对服务进行压测,发现性能确实有提升,也没有发生严重的 GC 问题,之后再把调整好的配置放到线上机器进行灰度,同时收集 gc log,再次进行分析。

由于 young 区大小翻倍了,所以 YGC 的频率减半了,GC 的吞量提升到了 97.75%。平均 GC 时长略有上升,从 60ms 左右提升到了 66ms,还是挺符合预期的。

由于 CMS 在进行 GC 时也会清理 young 区,CMS 的时长也受到了影响,CMS 的最终标记和并发清理阶段耗时增加了,也比较正常。

另外我还统计了对业务的影响,之前因为 GC 导致超时的请求大大减少了。

小结

总之,这是一次挺成功的 GC 调整,让我对 GC 有了更深的理解,但由于没有深入到 old 区,之前学习到的 CMS 相关的知识还没有复习到。

不过性能优化并不是一朝一夕的事,需要时刻关注问题,及时做出调整。

感谢您的阅读,也欢迎您发表关于这篇文章的任何建议,关注我,技术不迷茫!小编到你上高速。

· END ·

最后,关注公众号互联网架构师,在后台回复:2T,可以获取我整理的 Java 系列面试题和答案,非常齐全。

正文结束

推荐阅读 ↓↓↓

1.不认命,从10年流水线工人,到谷歌上班的程序媛,一位湖南妹子的励志故事

2.如何才能成为优秀的架构师?

3.从零开始搭建创业公司后台技术栈

4.程序员一般可以从什么平台接私活?

5.37岁程序员被裁,120天没找到工作,无奈去小公司,结果懵了...

6.IntelliJ IDEA 2019.3 首个最新访问版本发布,新特性抢先看

7.漫画:程序员相亲图鉴,笑屎我了~

8.15张图看懂瞎忙和高效的区别!

一个人学习、工作很迷茫?

点击「阅读原文」加入我们的小圈子!

一次简单的 JVM 调优,性能提升了15%相关推荐

  1. 记一次简单的 JVM 调优经历

    欢迎关注方志朋的博客,回复"666"获面试宝典 来源:https://zhenbianshu.github.io 背景 最近对负责的项目进行了一次性能优化,其中包括对 JVM 参数 ...

  2. 一次简单的 JVM 调优,拿去写到简历里

    前不久刚为一个项目调优了 GC ,还没来得及整理,今天在网上看到一篇调优文,先来分享一下. 来源地址:https://zhenbianshu.github.io 背景 最近对负责的项目进行了一次性能优 ...

  3. JVM调优,面到了阿里性能优化师!

    小K 菜哥,我看你朋友圈,你好像换工作了? 菜哥 对啊,前阵子被产品经理烦的头疼,就想换工作了.刚好找到一个不错的. 小K 给我说说呗,让我也参考一下,我现在工资才15K,主管死坑,我也想换工作了 菜 ...

  4. java jvm调优_(第2部分,共3部分):有关性能调优,Java中的JVM,GC,Mechanical Sympathy等的文章和视频的摘要...

    java jvm调优 这是以前的文章(第3部分,共1部分)的继续:有关性能调优,Java中的JVM,GC,Mechanical Sympathy等的文章和视频的提要 . 事不宜迟,让我们开始使用我们的 ...

  5. java jvm调优_(第1部分,共3部分):有关性能调优,Java中的JVM,GC,Mechanical Sympathy等的文章和视频的摘要...

    java jvm调优 我已经花了几个月的时间考虑审查有关性能调优,JVM,Java中的GC,Mechanical Sympathy等主题的文章和视频的缓存,并最终花了点时间–也许这就是重点我什么时候才 ...

  6. JVM调优全面探讨-性能设计沉思录(1)

    为什么要jvm gc可能是java程序猿或非java程序猿讨论最多的话题,到底怎么回事? 本篇内容:内存管理发展史,JVM内存管理分析和实践(基础知识),JVM8调优(内存运行原理和编译优化)  :2 ...

  7. jvm原理及性能调优系列(jvm调优)

    jvm原理及性能调优系列(jvm调优) JVM设置: 1.设置合适的最大堆内存(新生代和老生代的最大和值)和最小堆内存(jvm启动时占用的操作系统内存大小),及设置好堆的比例分配. 2.设置合适的新生 ...

  8. Java 性能优化系列之3.2[JVM调优]

    实用JVM参数 1. JIT 编译参数 JIT(Just-In-Time)编译器, 可以在运行时将字节码编译成本地代码,从而提升函数的执行效率. -XX:CompileThreshold为 JIT编译 ...

  9. JVM调优简单梳理,一分钟了解JVM调优

    JVM原理简单的认识         JVM指的是Sun公司的HotSpot JVM,JDK1.8之后JVM整合了JRockit 和 HotSpot的优点.JVM的行原理简历理解就是:JVM通过编译器 ...

  10. Java虚拟机这一块 —— JVM 调优和深入了解性能优化

    JVM 调优和深入了解性能优化 JVM 调优的本质 GC 调优原则 调优的原则 目的 GC 调优 调优步骤 日志分析 阅读 GC 日志 -XX:+UseSerialGC -XX:+UseParNewG ...

最新文章

  1. python 删除字符串中空格
  2. px4原生源码学习二--实时操作系统篇
  3. 【深度学习】——pytorch搭建模型及相关模型
  4. Sql语句之递归查询
  5. LeetCode 2103. 环和杆(位运算)
  6. android支付宝支付开发过程
  7. 基于JAVA+SpringMVC+Mybatis+MYSQL的物流管理系统
  8. SAP License:SAP顾问日记一
  9. Python 处理分析 128 张 Excel 表格竟不到3秒?| 附数据集
  10. 如何实现流水号二维码批量生成
  11. 【​观察】一部《天龙八部》,缘起“六脉神剑”
  12. 【C++---16】常指针和常引用
  13. 中关村物联网联盟启动10x10计划 解决物联网产业内冷外热发展难题
  14. JavaEE企业级实战项目 智牛股第五天 Netty的使用和项目数据库搭建
  15. 新基建时代的云生态 ——中国软件网“曹云社”走进浪潮
  16. 《 指数基金投资指南 》by 银行螺丝钉 - 笔记 - 4 - 第一部分
  17. 矩阵求导-YX拉伸术
  18. 3.5寸服务器硬盘v4,【02311REJ 960GB SSD SATA RH2288V3 V4华为服务器硬盘】价格_厂家 - 中国供应商...
  19. /includes/fckeditor/editor/filemanager/connectors/php/upload.php
  20. MacOS新晋神器——Raycast

热门文章

  1. 国庆宅家又羡慕别人的旅游美拍,教你一招轻松穿梭各大景点
  2. Day01 - 打开Linux大门
  3. linux 下ifconfig修改IP
  4. ARM计划将四核心CPU引入磁盘驱动器
  5. mysql备份恢复中的常见错误
  6. IPv4与IPv6数据报格式详解
  7. I.MX6 android 禁止低电量自动关机
  8. php中echo(),print(),print_r()的区别
  9. 聆听自由的声音----Linux下声卡驱动软件ALSA的安装与配置
  10. 解析函数论 Page 8 $f(x)$在$x_0$处解析的充要条件