0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何解决JDK8小版本升级后性能下降的问题

Rokr_wireless_t 来源:openEuler 作者:openEuler 2021-07-26 14:44 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

编者按:在升级 JDK8U 的小版本后(从 8u74 升级到 8u202),遇到性能剧烈下降的问题(性能下降 13 倍)。该应用是一个非常简单的 Web 应用,且应用在 JDK 升级前后并无任何发布修复。

通常来说 JDK 小版本升级都是问题修改,不影响功能和性能使用,而应用性能剧烈下降一定是 JDK 的内部 bug。对于这样明确由 JDK 引起的性能问题,该如何解决?

最常见的方法是通过工具分析 JVM 执行过程,检查函数执行的情况是否发生变化,如果找到变化,则可以深入分析哪些因素引起了变化,并进一步得到根因。笔者使用 perf 工具分析 JVM 执行时的热点函数,并对出现问题的函数进行剖析,使用函数插桩来分析函数的执行次数,发现不同版本行为差异的根源,并找到了引起问题的根因。希望读者遇到性能问题时可以参照本文使用 perf 工具对问题进行定位。

工欲善其事,必先利其器。程序员在定位性能瓶颈的时候,要是有一个趁手的性能调优工具,能一针见血地指出程序的性能问题,可谓事半功倍。

Linux 中最常用的性能调优工具 Perf(Linux 系统原生提供的性能分析工具),使用 perf 先对应用(假设要采样的应用为 JavaApp)进行采样,使用 record 命令,如下:

perfrecordjavaJavaApp

另外 perf 能按出现的百分比降序打印 CPU 正在执行的函数名以及调用栈,如命令:

perfreport-n

这种结果的输出还是不直观的,Linux 性能优化大师 Brendan Gregg 发明了火焰图(因整个图形看起来像燃烧的火焰而得名),以全局的方式来看各个函数的调用时间分布,以图形化的方式列出调用栈。

火焰图是基于 perf 的结果生成的图形,我们先了解一下怎么去看火焰图。

X 轴表示被抽样到的次数。理解 X 轴的含义,需先了解采样数据的原理。Perf 是在指定时间段内,每隔一段时间采集一次数据,被采集到的次数越多,说明该函数的执行总时间长,可能的原因有:调用次数多,或者单次执行时间长。因此,X 轴的宽度不能简单的认为是运行时长。Y 轴表示调用栈。

如何从火焰图看出性能的瓶颈在哪里?最有理由怀疑的地方,顶层的“平顶”。关于 perf 和火焰图使用方法可以参官网http://www.brendangregg.com/FlameGraphs/cpuflamegraphs.html。

下面是我们利用火焰图来定位问题的一次实战。

火焰图定位问题的实战

问题场景

问题发生的场景是客户端向服务器发起 http 请求,服务器返回数据给客户端(这是一个非常简单的服务交互)。我们发现使用 JDK 8u74 的性能要远优于 JDK 8u202 的性能,下表中统计了 20 次服务器的响应时长。

009cbc14-e029-11eb-9e57-12bb97331649.png

从响应时间来看,8u202 相比 8u74 性能下降 13 倍之多,由于应用本身并未做任何修改,所以考虑使用火焰图来定位性能消耗的问题点。在 8u74 和 8u202 分别运行应用,并用 perf 的 record 抓取数据并生成火焰图。

火焰图定位

对比两张火焰图,使用 8u74 时 ClientHandshaker.processMessage 占比为 1.15%,而在 8u202 中这个函数占比为 23.98%,很明显在 ClientHandshaker.processMessage 带来了性能差异。

00c5357c-e029-11eb-9e57-12bb97331649.png

01225572-e029-11eb-9e57-12bb97331649.png

根因定位

两者在这个 ClientHandshaker.processMessage 上的 cpu 消耗差异很大,继续分析这个函数找到根因。

voidprocessMessage(bytehandshakeType,intlength)throwsIOException{ if(this.state>=handshakeType&&handshakeType!=0){ //...异常 }else{ label105: switch(handshakeType){ case0://hello_request this.serverHelloRequest(newHelloRequest(this.input)); break; //... case2://sever_hello this.serverHello(newServerHello(this.input,length)); break; case11:///certificate this.serverCertificate(newCertificateMsg(this.input)); this.serverKey=this.session.getPeerCertificates()[0].getPublicKey(); break; case12://server_key_exchange该消息并不是必须的,取决于协商出的key交换算法 //... case13://certificate_request客户端双向验证时需要 //... case14://server_hello_done this.serverHelloDone(newServerHelloDone(this.input)); break; case20://finished this.serverFinished(newFinished(this.protocolVersion,this.input,this.cipherSuite)); } if(this.state< handshakeType) {//握手状态             this.state = handshakeType;         }     } }

processMessage()主要是通过不同的信息类型进行不同的握手消息的处理。而在火焰图中可以看到,JDK8u74 图中,主要消耗在函数 serverFinished()和 serverHello()上,而 JDK8u202 主要消耗在函数 serverHelloDone()和 serverKeyExchange()。

在介绍火焰图的时候,我们有提到,X 轴的长度是映射了被采样到的次数。因此需要进一步确定消耗:函数单次执行耗时过长而成为热点,还是因为频繁调用函数导致函数耗时过长而成为热点。

可通过字节码插桩(通过 Instrument 技术实现对函数的计数,然后编译成 agent,执行应用时加载 agent,具体使用 Instrument 的方法可以参考官方文档)查看函数 serverHelloDone()的调用次数及执行时间。

JDK8u202数据 Executecount:253 Executecount:258 Executecount:649 Executecount:661 serverHelloDoneexecutetime[1881195ns] Executecount:1223 Executecount:1234 Executecount:1843 Executecount:1852 serverHelloDoneexecutetime[1665012ns] Executecount:2446 Executecount:2456 serverHelloDoneexecutetime[1686206ns] JDK8u74数据 Executecount:56 Executecount:56 Executecount:56 Executecount:56 Executecount:56 Executecount:56

Execute time 是取了每 1000 次调用的平均值,Execute count 每 5000ms 输出一次总执行次数。很明显使用 JDK8u202 时在不断调用 serverHelloDone,而 74 在调用 56 次后没有再调用过这个函数。

初始化握手时,serverHelloDone 方法中,客户端会根据服务端返回加密套件决定加密方式,构造不同的 Client Key Exchange 消息;服务器如果允许重用该会话,则通过在 Server Hello 消息中设置相同的会话 ID 来应答。

这样,客户端和服务器就可以利用原有会话的密钥和加密套件,不必重新协商,也就不再走 serverHelloDone 方法。从现象来看, JDK8u202 没有复用会话,而是建立的新的会话。

水落石出

查看 JDK8u 161 的 release notes,添加了 TLS 会话散列和扩展主密钥扩展支持,找到引入的一个还未修复的 issue,对于带有身份验证的 TLS 的客户端,支持 UseExtendedMasterSecret 会破坏 TLS-Session 的恢复,导致不使用现有的 TLS-Session,而执行新的 Handshake。

JDK8u161 之后的版本(含 JDK8u161),若复用会话时不能成功恢复 Session,而是创建新的会话,会造成较大性能消耗,且积压的大量的不可复用的 session 造成 GC 压力变大;如果业务场景存在不变更证书密钥,需要复用会话,且对性能有要求,可通过添加参数-Djdk.tls.useExtendedMasterSecret=false 来解决这个问题。

后记

如果遇到相关技术问题(包括不限于毕昇 JDK),可以通过毕昇 JDK 社区求助。毕昇 JDK 社区每双周周二举行技术例会,同时有一个技术交流群讨论 GCC、LLVM 和 JDK 等相关编译技术,感兴趣的同学可以添加如下微信小助手入群(请备注:Complier)。

编辑:jq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • jdk8
    +关注

    关注

    0

    文章

    4

    浏览量

    2037

原文标题:使用 perf 解决 JDK8 小版本升级后性能下降的问题

文章出处:【微信号:wireless-tag,微信公众号:启明云端科技】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    IvorySQL开源社区正式发布IvorySQL 5.0版本

    近日,IvorySQL开源社区正式发布IvorySQL 5.0版本。该版本基于PostgreSQL 18.0进行全面迭代升级,在Oracle兼容性上实现新突破,生态组件集成能力持续进阶,同时深度适配云原生场景,同步提供全平台安装
    的头像 发表于 12-04 10:06 306次阅读
    IvorySQL开源社区正式发布IvorySQL 5.0<b class='flag-5'>版本</b>

    Quartus Prime Pro 25.1版本的安装和使用

    如果用户开发板是基于Agilex 3、Agilex 5等高阶器件,则需要安装高版本的Quartus软件比如Quartus Prime Pro 25.1版本,这个版本在安装包和license获取(免费)等方面跟以往的Quartus
    的头像 发表于 10-07 13:06 2048次阅读
    Quartus Prime Pro 25.1<b class='flag-5'>版本</b>的安装和使用

    Perforce QAC 2025.2版本更新:虚拟内存优化、100%覆盖CERT C规则、CI构建性能提升等

    【产品更新】Perforce QAC更新至2025.2版本,安装路径和许可证都有变化!重点:虚拟内存占用降低、100%覆盖CERT C规则,C23支持增强、CI构建性能提升等。建议尽快评估升级
    的头像 发表于 09-09 14:40 434次阅读
    Perforce QAC 2025.2<b class='flag-5'>版本</b>更新:虚拟内存优化、100%覆盖CERT C规则、CI构建<b class='flag-5'>性能</b>提升等

    开鸿Bot系列V5.0.1.10版本升级

    开鸿Bot系列更新至V5.0.1.10版本,此次升级聚焦功能优化及系统稳定性提升,在分布式能力、文件分享、打印功能及界面显示等方面进行了多项改进,同时修复了多个已知问题,进一步提升了系统的可靠性
    的头像 发表于 08-08 18:58 424次阅读
    开鸿Bot系列V5.0.1.10<b class='flag-5'>版本</b><b class='flag-5'>升级</b>!

    求助,关于STM32Cubemx 6.15版本生成工程的文件编码的问题求解

    之前升级6.13和6.14版本的时候重新生成工程会将文件编码强制转换成UTF-8格式,导致中文注释乱码。但是在安装文件夹下面的STM32CubeMX.l4j.ini文件里面添加一行
    发表于 07-29 12:31

    VA One 2024版本的关键升级

    自 2005 年发布以来,VA One 已广泛应用于汽车、航空航天、船舶等多个行业领域。VA One 开发团队每年都会对软件进行功能迭代与优化,目前最新版本为 VA One 2024。与以往版本
    的头像 发表于 07-14 16:09 1091次阅读
    VA One 2024<b class='flag-5'>版本</b>的关键<b class='flag-5'>升级</b>

    性能升级!开鸿Bot系列V4.1.2.78.002版本发布

    开鸿BotBook和开鸿BotMini迎来V4.1.2.78.002版本升级本次升级聚焦用户体验优化重点优化了系统功能、浏览器功能开发者体验功能等带来更流畅、更高效的操作体验01系统功能优化蓝牙耳机
    的头像 发表于 07-11 19:53 462次阅读
    <b class='flag-5'>性能</b>再<b class='flag-5'>升级</b>!开鸿Bot系列V4.1.2.78.002<b class='flag-5'>版本</b>发布

    开鸿BotBook和开鸿BotMini新版本来了!

    今日,开鸿Bot系列迎来最新升级!开鸿BotBook升级至V4.1.2.77版本,开鸿BotMini升级至V4.1.2.71版本。此次
    的头像 发表于 06-27 20:52 891次阅读
    开鸿BotBook和开鸿BotMini新<b class='flag-5'>版本</b>来了!

    兆松科技发布高性能RISC-V编译器ZCC 4.0.0版本

    近日,兆松科技(武汉)有限公司(以下简称“兆松科技”)宣布正式发布高性能 RISC-V 编译器 ZCC 4.0.0 版本。新版本性能优化、厂商自定义指令支持和软件库等方面实现全面
    的头像 发表于 06-27 14:48 2250次阅读
    兆松科技发布高<b class='flag-5'>性能</b>RISC-V编译器ZCC 4.0.0<b class='flag-5'>版本</b>

    JDK8升级到21的问题集

    一、背景与挑战 1. 升级动因 ◦Oracle长期支持策略 ◦现代特性需求:协程、模式匹配、ZGC等 ◦安全性与性能的需求 ◦AI新技术引入的版本要求 2. 项目情况 ◦100+项目并行升级
    的头像 发表于 06-06 16:49 592次阅读

    摩尔线程发布Torch-MUSA v2.0.0版本 支持原生FP8和PyTorch 2.5.0

    近日,摩尔线程正式发布Torch-MUSA v2.0.0版本,这是其面向PyTorch深度学习框架的MUSA扩展库的重要升级。新版本基于MUSA Compute Capability 3.1计算架构
    的头像 发表于 05-11 16:41 1273次阅读

    迅为RK3568多个系统版本并流畅运行Android12和11版本

    方案。 核心板提供连接器与邮票孔两种,商业级2G、商业级4G、商业级8G工业级2G、工业级4G、国产化工业级2G多种核心板引脚兼容,适用于同一底板,产品升级自如,适用于各个应用场合。 底板分为连接器
    发表于 04-14 16:20

    motorBench 2.45.0版本说明

    电子发烧友网站提供《motorBench 2.45.0版本说明.pdf》资料免费下载
    发表于 01-22 16:15 0次下载
    motorBench 2.45.0<b class='flag-5'>版本</b>说明

    OurBMC 24.12版本正式上线

    日前,经过社区开发者的共同努力,OurBMC 全新升级,24.12版本正式上线。
    的头像 发表于 01-07 13:45 1297次阅读

    STM32F103上位机升级,RS485升级、CAN升级

    自己项目需求修改上位机。 我们提供版本升级例程. 1、带外置Flash的裸机版本 2、带外置Flash的FreeRTOS版本 3、不带
    发表于 01-03 08:57