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

通过这一个多月的努力,将 FullGC 从 40 次/天优化到近 10 天才触发一次,而且 YoungGC 的时间也减少了一半以上,这么大的优化,有必要记录一下中间的调优过程。

对于JVM垃圾回收,之前一直都是处于理论阶段,就知道新生代,老年代的晋升关系,这些知识仅够应付面试使用的。前一段时间,线上服务器的FullGC非常频繁,平均一天40多次,而且隔几天就有服务器自动重启了,这表明的服务器的状态已经非常不正常了,得到这么好的机会,当然要主动请求进行调优了。未调优前的服务器GC数据,FullGC非常频繁。

首先服务器的配置非常一般(2核4G),总共4台服务器集群。每台服务器的FullGC次数和时间基本差不多。其中JVM几个核心的启动参数为:

-Xms1000M -Xmx1800M -Xmn350M -Xss300K -XX:+DisableExplicitGC -XX:SurvivorRatio=4 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSParallelRemarkEnabled -XX:LargePageSizeInBytes=128M -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:+PrintHeapAtGC

-Xmx1800M:设置JVM最大可用内存为1800M。-Xms1000m:设置JVM初始化内存为1000m。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。-Xmn350M:设置年轻代大小为350M。整个JVM内存大小=年轻代大小 + 年老代大小 + 持久代大小。持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。

此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。-Xss300K:设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。更具应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。

第一次优化

一看参数,马上觉得新生代为什么这么小,这么小的话怎么提高吞吐量,而且会导致YoungGC的频繁触发,如上如的新生代收集就耗时830s。初始化堆内存没有和最大堆内存一致,查阅了各种资料都是推荐这两个值设置一样的,可以防止在每次GC后进行内存重新分配。基于前面的知识,于是进行了第一次的线上调优:提升新生代大小,将初始化堆内存设置为最大内存

-Xmn350M -> -Xmn800M -XX:SurvivorRatio=4 -> -XX:SurvivorRatio=8 -Xms1000m ->-Xms1800m

将SurvivorRatio修改为8的本意是想让垃圾在新生代时尽可能的多被回收掉。就这样将配置部署到线上两台服务器(prod,prod2另外两台不变方便对比)上后,运行了5天后,观察GC结果,YoungGC减少了一半以上的次数,时间减少了400s,但是FullGC的平均次数增加了41次。YoungGC基本符合预期设想,但是这个FullGC就完全不行了。

就这样第一次优化宣告失败。

第二次优化

在优化的过程中,我们的主管发现了有个对象T在内存中有一万多个实例,而且这些实例占据了将近20M的内存。于是根据这个bean对象的使用,在项目中找到了原因:匿名内部类引用导致的,伪代码如下:

public void doSmthing(T t){redis.addListener(new Listener(){public void onTimeout(){if(t.success()){//执行操作}}});
}

由于listener在回调后不会进行释放,而且回调是个超时的操作,当某个事件超过了设定的时间(1分钟)后才会进行回调,这样就导致了T这个对象始终无法回收,所以内存中会存在这么多对象实例。通过上述的例子发现了存在内存泄漏后,首先对程序中的error log文件进行排查,首先先解决掉所有的error事件。然后再次发布后,GC操作还是基本不变,虽然解决了一点内存泄漏问题,但是可以说明没有解决根本原因,服务器还是继续莫名的重启。

内存泄漏调查

经过了第一次的调优后发现内存泄漏的问题,于是大家都开始将进行内存泄漏的调查,首先排查代码,不过这种效率是蛮低的,基本没发现问题。于是在线上不是很繁忙的时候继续进行dump内存,终于抓到了一个大对象。

这个对象竟然有4W多个,而且都是清一色的ByteArrowRow对象,可以确认这些数据是数据库查询或者插入时产生的了。于是又进行一轮代码分析,在代码分析的过程中,通过运维的同事发现了在一天的某个时候入口流量翻了好几倍,竟然高达83MB/s。

经过一番确认,目前完全没有这么大的业务量,而且也不存在文件上传的功能。咨询了云服务器客服也说明完全是正常的流量,可以排除攻击的可能。

就在我还在调查入口流量的问题时,另外一个同事找到了根本的原因,原来是在某个条件下,会查询表中所有未处理的指定数据,但是由于查询的时候where条件中少加了模块这个条件,导致查询出的数量达40多万条,而且通过log查看当时的请求和数据,可以判断这个逻辑确实是已经执行了的,dump出的内存中只有4W多个对象,这个是因为dump时候刚好查询出了这么多个,剩下的还在传输中导致的。而且这也能非常好的解释了为什么服务器会自动重启的原因

解决了这个问题后,线上服务器运行完全正常了,使用未调优前的参数,运行了3天左右FullGC只有5次:

第三次调优

内存泄漏的问题已经解决了,剩下的就可以继续调优了,经过查看GC log,发现前三次GullGC时,老年代占据的内存还不足30%,却发生了FullGC。另外,微信搜索互联网架构师,在后台发送:2T,可以获取一份完整的 JVM 调优指南。

于是进行各种资料的调查,在:https://blog.csdn.net/zjwstz/article/details/77478054 博客中非常清晰明了的说明metaspace导致FullGC的情况,服务器默认的metaspace是21M,在GC log中看到了最大的时候metaspace占据了200M左右,于是进行如下调优,以下分别为prod1和prod2的修改参数,prod3,prod4保持不变。

-Xmn350M -> -Xmn800M -Xms1000M ->1800M -XX:MetaspaceSize=200M -XX:CMSInitiatingOccupancyFraction=75

-Xmn350M -> -Xmn600M -Xms1000M ->1800M -XX:MetaspaceSize=200M -XX:CMSInitiatingOccupancyFraction=75

prod1和2只是新生代大小不一样而已,其他的都一致。到线上运行了10天左右,进行对比:prod1:

prod2:

prod3:

prod4:

对比来说,1,2两台服务器FullGC远远低于3,4两台,而且1,2两台服务器的YounGC对比3,4也减少了一半左右,而且第一台服务器效率更为明显,除了YoungGC次数减少,而且吞吐量比多运行了一天的3,4两台的都要多(通过线程启动数量),说明prod1的吞吐量提升尤为明显。通过GC的次数和GC的时间,本次优化宣告成功,且prod1的配置更优,极大提升了服务器的吞吐量和降低了GC一半以上的时间。

prod1中的唯一一次FullGC:

通过GC log上也没看出原因,老年代在cms remark的时候只占据了660M左右,这个应该还不到触发FullGC的条件,而且通过前几次的YoungGC调查,也排除了晋升了大内存对象的可能,通过metaspace的大小,也没有达到GC的条件。这个还需要继续调查,有知道的欢迎指出下,这里先行谢过了。

总结

通过这一个多月的调优总结出以下几点:

  • FullGC一天超过一次肯定就不正常了

  • 发现FullGC频繁的时候优先调查内存泄漏问题

  • 内存泄漏解决后,jvm可以调优的空间就比较少了,作为学习还可以,否则不要投入太多的时间

  • 如果发现CPU持续偏高,排除代码问题后可以找运维咨询下云服务器客服,这次调查过程中就发现CPU 100%是由于服务器问题导致的,进行服务器迁移后就正常了。

  • 数据查询的时候也是算作服务器的入口流量的,如果访问业务没有这么大量,而且没有攻击的问题的话可以往数据库方面调查

  • 有必要时常关注服务器的GC,可以及早发现问题

以上是最近一个多月JVM调优的过程与总结,如有错误之处欢迎指正。

原文链接:https://blog.csdn.net/cml_blog/article/details/81057966

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

· END ·

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

正文结束

推荐阅读 ↓↓↓

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

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

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

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

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

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

7.这封“领导痛批95后下属”的邮件,句句扎心!

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

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

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

JVM 调优一个月,性能提升了 400 倍!相关推荐

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

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

  2. jvm调优工具_JVM性能调优监控工具jps、jstack、jmap、jhat、hprof使用详解

    来自:ITeye博客, 作者:Josh_Persistence 链接:https://www.iteye.com/blog/josh-persistence-2161848 现实企业级Java应用开发 ...

  3. jvm调优工具_JVM性能调优监控工具jps、jstack、jmap、jhat、jstat、hprof使用

    现实企业级Java应用开发.维护中,有时候我们会碰到下面这些问题: OutOfMemoryError,内存不足 内存泄露 线程死锁 锁争用(Lock Contention) Java进程消耗CPU过高 ...

  4. Spring boot、Redis、ActiveMQ、Nginx、Mycat、Netty、Jvm调优

    性能优化 JVM调优 Java程序性能优化 Tomcat Mysql Spring IOC Spring AOP Spring MVC Spring 5新特性 Mybatis 分布式架构 架构核心服务 ...

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

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

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

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

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

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

  8. 【经验】通过JVM调优,让凯哥个人博客响应速度提升了不少

    为什么你的个人博客访问慢? 不知道大家有没有注意到,在22.10.31 21点之后,凯哥的个人博客站点(凯哥Java:www.kaigejava.com)访问速度提升了不少.那是因为凯哥对站点做了优化 ...

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

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

  10. 技能篇:linux服务性能问题排查及jvm调优思路

    只要业务逻辑代码写正确,处理好业务状态在多线程的并发问题,很少会有调优方面的需求.最多就是在性能监控平台发现某些接口的调用耗时偏高,然后再发现某一SQL或第三方接口执行超时之类的.如果你是负责中间件或 ...

最新文章

  1. PAT(甲级)2018年冬季考试 7-4 Heap Paths(非递归与递归解法)
  2. 利用计算思维解决问题人和计算机都能完成,第1课计算机与计算思维.ppt
  3. 阳江市2021高考成绩查询一下,广东省阳江市2021年高级会计师考试结束后去哪查成绩?...
  4. IOS - JSON数据解析 小3种方法
  5. 转载--让搜索引擎优化(SEO)更有效 CSS+DIV标签命名规范
  6. python设置循环范围_python – 如何检查循环范围的重叠(重叠的年度循环周期)
  7. 2021 整理的最全学习资源,送给每一个努力着的人
  8. 第七章—JavaScript数组
  9. 推荐系统经典模型 Wide Deep 论文剖析
  10. java实时检测_JAVA 实时检测二进制流字符集
  11. linux Socket send与recv函数详解
  12. 基于各国贷款数据的可视化分析(含python代码)
  13. 脚本的使用与修改Tampermonkey(油猴)
  14. amd opencl使用低版本驱动
  15. 微软云服务器搭建,75分钟快速构建微软Server 2012私有云
  16. Bootstrap框架使用及可视化布局
  17. office起动缓慢_怎么解决Office2016启动特别慢?
  18. c语言检测邮箱地址,C语言实现电子邮件地址验证程序
  19. TreeSet引发的OSGI服务代理创建异常
  20. android ios图片丢失,如何恢复iPhone、安卓智能手机上误删、丢失的图片?

热门文章

  1. iOS底层探索之Block(一)——初识Block(你知道几种Block呢?)
  2. 光声光谱技术和激光、红外技术的优劣势对比
  3. textarea中输入多个空格或者换行时只显示一个空格的解决办法
  4. dede 鼠标移到标题处显示完整标题
  5. 网上招生报名系统V1.0发布
  6. Linux下mail服务配置(RHEL5)
  7. winform最小化后隐藏到右下角,单击或双击后恢复
  8. C++ 什么叫做离散化
  9. 苹果mac菜单栏应用管理软件Bartender 让Mac选项列不再拥挤
  10. 如何从Mac桌面隐藏各种标准图标?