jvm调优一个月,性能提升了400倍!(代码片段)

Java技术栈 Java技术栈     2022-12-05     195

关键词:

通过这一个多月的努力,将 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。于是进行各种资料的调查,在: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

版权声明:本文为CSDN博主「cmlbeliever」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

近期热文推荐:

1.1,000+ 道 Java面试题及答案整理(2021最新版)

2.终于靠开源项目弄到 IntelliJ IDEA 激活码了,真香!

3.阿里 Mock 工具正式开源,干掉市面上所有 Mock 工具!

4.Spring Cloud 2020.0.0 正式发布,全新颠覆性版本!

5.《Java开发手册(嵩山版)》最新发布,速速下载!

觉得不错,别忘了随手点赞+转发哦!

jvm调优一个月,性能提升了400倍!

...半以上,这么大的优化,有必要记录一下中间的调优过程。对于JVM垃圾回收,之前一直都是处于理论阶段,就知道新生代,老 查看详情

jvm调优一个月,性能提升了400倍!

...半以上,这么大的优化,有必要记录一下中间的调优过程。对于JVM垃圾回收,之前一直都是处于理论阶段,就知道新生代,老年代的晋升关系, 查看详情

一次简单的jvm调优,性能提升了15%

...化,其中包括对JVM参数的调整,算是进行了一次简单的JVM调优,JVM参数调整之后,服务的整体性能有15%左右的提升,还算不错。先介绍一下项目的基本情况:项目是一个高QPS压力的web服务,单机QPS一直维持在1.5K以上,由于旧机... 查看详情

jvm调优总结

 写在之前的话最近在工作中总是遇到服务的QPS在压测的时间比较低的情况。于是就开始了性能优化之旅,这个过程是很是曲折。一开始的时候认为是服务的业务逻辑比较多,大部分的时间都花在优化业务逻辑,减少与其他服... 查看详情

我只改五行代码,接口性能提升了10倍!(代码片段)

背景某公司的一个ToB系统,因为客户使用的也不多,没啥并发要求,就一直没有经过压测。这两天来了一个“大客户”,对并发量提出了要求:核心接口与几个重点使用场景单节点吞吐量要满足最低500/s的要求... 查看详情

day800.jvm内存分配优化-java性能调优实战(代码片段)

...是阿昌,今天学习记录的是关于JVM内存分配优化。JVM调优是一个系统而又复杂的过程,在大多数情况下,基本不用去调整JVM内存分配,因为一些初始化的参数已经可以保证应用服务正常稳定地工作了。但所有的调... 查看详情

day800.jvm内存分配优化-java性能调优实战(代码片段)

...是阿昌,今天学习记录的是关于JVM内存分配优化。JVM调优是一个系统而又复杂的过程,在大多数情况下,基本不用去调整JVM内存分配,因为一些初始化的参数已经可以保证应用服务正常稳定地工作了。但所有的调... 查看详情

jvm常用调优参数——jvm篇(代码片段)

JVM常用性能调优参数详解​在学习完整个JVM内容后,其实目标不仅是学习了解整个JVM的基础知识,而是为了进行JVM性能调优做准备,所以以下的内容就是来说说JVM性能调优的知识。一、性能调优​性能调优包含多个层... 查看详情

day797.jvm内存模型-java性能调优实战(代码片段)

...会有人问到:请讲解下JVM的内存模型,JVM的性能调优做过吗?一、为什么JVM在Java中如此重要?首先应该知道,运行一个Java应用程序,必须要先安装JDK或者JR 查看详情

使用apachespark对mysql调优查询速度提升10倍以上

在这篇文章中我们将讨论如何利用ApacheSpark来提升MySQL的查询性能。介绍  在我的前一篇文章 ApacheSparkwithMySQL 中介绍了如何利用ApacheSpark实现数据分析以及如何对大量存放于文本文件的数据进行转换和分析。瓦迪姆还做... 查看详情

jvm性能调优(代码片段)

jvm性能调优一、jvm内存模型二、目标在以下三点中,通过修改jvm参数寻找平衡。GC的时间足够的小GC的次数足够的少发生FullGC的周期足够的长三、方法减少使用全局变量和大对象;调整新生代的大小到最合适;设置老年代的大小... 查看详情

jvm性能调优监控工具jpsjmapjstackjstat使用详解(代码片段)

JDK本身提供了很多方便的JVM性能调优监控工具,除了集成式的VisualVM和jConsole外,还有jps、jstack、jmap、jhat、jstat等小巧的工具,本博客希望能起抛砖引玉之用,让大家能开始对JVM性能调优的常用工具有所了解。现... 查看详情

jvm内存调优(代码片段)

JVM性能调优有很多设置,这个参考JVM参数即可.主要调优的目的:控制GC的行为.GC是一个后台处理,但是它也是会消耗系统性能的,因此经常会根据系统运行的程序的特性来更改GC行为控制JVM堆栈大小.一般来说,JVM在内存分配上不需要你... 查看详情

jvm系列之性能调优参考手册(实践篇)(代码片段)

JVM系列之性能调优参考手册(实践篇)系列博客专栏:JVM系列博客专栏SpringBoot系列博客1、前言介绍在前面章节的学习,我们对JVM的体系架构等等有了比较详细的了解,所以可以对这些理论进行实践,当然... 查看详情

jvm性能调优实战:让你的intellijidea纵享丝滑(代码片段)

...elliJIdea,本篇就使用工具来实战演练对IntelliJIdea运行速度调优调优前的运行状态原始配置内容要查询idea原始配置文件的路径可以在VisualVM中的概述 查看详情

jvm性能优化对象内存分配之虚拟机参数调优分析(代码片段)

...文主要针对于综合层面上进行分析JVM优化方案总结和列举调优参数计划。主要包含:调优之逃逸分析(栈上分配)调优之线程局部缓存(TLAB)调优之G1回收器栈上分配与逃逸分析-XX:+DoEscapeAnalysis逃逸分析(Esc... 查看详情

day355.性能监控与调优概述-jvm(代码片段)

...器分配多少内存合适?如何对垃圾回收器的性能进行调优?生产环境CPU负载飙高该如何处理?生产环境应该给应用分配多少线程合适?不加log,如何确定请求是否执行了某一行代码?不加log,如何实时... 查看详情

jvm性能调优

  JVM技术图谱 性能调优性能调优包含多个层次,比如:架构调优、代码调优、JVM调优、数据库调优、操作系统调优等。架构调优和代码调优是JVM调优的基础,其中架构调优是对系统影响最大的。性能调优基本上按照以... 查看详情