JDK11现存性能bug(JDK-8221394)深度解析(2)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
云解析DNS,个人版 1个月
简介: 当然这个bug的本质就是jdk11+zgc+StackWalker的bug,三者都是bug触发的必要条件,如果你能避免其中一条就可以完美避开这个bug了,比如升级到jdk12+,比如不用zgc……

避坑指南

如果你看懂了上文的bug原理,相信你已经知道了如何闭坑,如果没看懂也没关系, 一句话 不要使用jdk11+zgc的同时频繁使用StackWalker(比如错误使用log4j)。当然也不是完全不能使用log4j了,只要不是频繁调用StackWalker就没问题,像我们代码中的logger只需要声明成static,这样StackWalker只会在类初始化的时候调用,就不会有问题了。知道了原理,也就能解释清楚为什么我们很多其他应用用了jdk11也用了有问题的RedisClient没有出现cpu异常的现象,就是因为其他应用没有启用zgc。


当然这个bug的本质就是jdk11+zgc+StackWalker的bug,三者都是bug触发的必要条件,如果你能避免其中一条就可以完美避开这个bug了,比如升级到jdk12+,比如不用zgc……


Bugfix

对于我们应用来说,只需按照上面的避坑指南操作即可,但对于jdk团队来说,这个bug他们肯定是要修复的。

a6cf3751bc08a5a8bed96c663c79b779_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hpbmRvbw==,size_16,color_FFFFFF,t_70#pic_center.png

从官网bug页面可以看到这个bug在jdk13中已经修复了,我们来看看他们是如何修复的。是不是只需要在zgc合适的地方调一下SymbolTable::unlink()就行了?是的,但jdk团队做的远不止于此,除了unlink之外,他们还优化了ResolvedMethodTable的实现,支持了动态扩缩容,可以避免单链表过长的问题,具体可以看下jdk源码中src/hotspot/share/prims/resolvedMethodTable.cpp的文件。


void ResolvedMethodTable::do_concurrent_work(JavaThread* jt) {
  _has_work = false;
  double load_factor = get_load_factor();
  log_debug(membername, table)("Concurrent work, live factor: %g", load_factor);
  // 人工load_factor大于2,并且没有达到最大限制,就执行bucket扩容,并且移除无用的entry
  if (load_factor > PREF_AVG_LIST_LEN && !_local_table->is_max_size_reached()) {
    grow(jt);
  } else {
    clean_dead_entries(jt);
  }
}
void ResolvedMethodTable::grow(JavaThread* jt) {
  ResolvedMethodTableHash::GrowTask gt(_local_table);
  if (!gt.prepare(jt)) {
    return;
  }
  log_trace(membername, table)("Started to grow");
  {
    TraceTime timer("Grow", TRACETIME_LOG(Debug, membername, table, perf));
    while (gt.do_task(jt)) {
      gt.pause(jt);
      {
        ThreadBlockInVM tbivm(jt);
      }
      gt.cont(jt);
    }
  }
  gt.done(jt);
  _current_size = table_size();
  log_info(membername, table)("Grown to size:" SIZE_FORMAT, _current_size);
}


总结

这个bug触发的主要原因其实还是我们自己的代码写的不够规范(logger未声明为static),而这个不规范其实也对其他没有触发这个bug的应用也产生了影响,毕竟生成logger也是会消耗性能的,我们代码fix后其他应用升级,有些服务CPU占用率降低5%+。这也充分说明代码质量的重要性,尤其是那种被广泛采用的基础代码。


另外是不是有些人还有个疑问,这个bug为什么不在jdk11后续版本中修掉,而是选择在jdk13中彻底修掉,不怕影响到使用jdk11的用户吗?对这个问题我有个想法,其实这个bug并不是很容易触发的严重bug(jdk11+zgc+log4j的频繁调用),而且即便是触发了,jdk的使用者也很容易通过修改自己的代码来规避这个bug,所以对jdk的开发者而言这不是一个重要且紧急的bug,后续修复掉就行了。


参考资料

阿里巴巴开源java问题排查工具 Arthas.

如何读懂火焰图? 阮一峰

jdk开发者关于bug讨论的邮件列表

目录
相关文章
|
5天前
|
Oracle NoSQL 固态存储
阿里云服务器ESSD Entry云盘与ESSD云盘选择指南:性能与场景解析
在我们选择阿里云服务器的时候,有部分云服务器同时支持ESSD Entry云盘和ESSD云盘,选择不同的云盘,价格也有所差异,有的用户还不清楚他们之间的区别,因此不知道选择哪种更好更能满足自己场景的需求,本文为大家介绍一下阿里云服务器ESSD Entry云盘和ESSD云盘的区别及选择参考。
阿里云服务器ESSD Entry云盘与ESSD云盘选择指南:性能与场景解析
|
8天前
|
SQL 运维 监控
MSSQL性能调优深度解析:索引优化策略、SQL查询优化技巧与高效并发管理实践
在Microsoft SQL Server(MSSQL)的运维与优化领域,性能调优是确保数据库高效运行、满足业务需求的关键环节
|
8天前
|
SQL 存储 监控
MSSQL性能调优深度解析:索引策略优化、SQL语句精炼与并发管理技巧
在Microsoft SQL Server(MSSQL)的性能调优领域,索引策略的优化、SQL语句的精炼以及高效的并发管理技巧是提升数据库性能不可或缺的三大方面
|
8天前
|
SQL 运维 监控
MSSQL性能调优深度解析:索引精细调整、SQL查询优化与并发控制策略
在Microsoft SQL Server(MSSQL)的运维实践中,性能调优是确保数据库高效、稳定运行的核心任务
|
8天前
|
SQL 运维 数据库
MSSQL性能调优深度解析:索引优化策略、查询优化技巧与并发控制实践
在Microsoft SQL Server(MSSQL)的运维与优化旅程中,性能调优无疑是每位数据库管理员和开发者的必修课
|
10天前
|
IDE Oracle Java
day4:JDK、IntelliJ IDEA的安装和环境变量配置
【7月更文挑战第4天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
29 0
|
6天前
|
存储 Ubuntu Java
【Linux】已解决:Ubuntu虚拟机安装Java/JDK
【Linux】已解决:Ubuntu虚拟机安装Java/JDK
12 1
|
19天前
|
Linux 测试技术 开发工具
CentOS Linux 8使用阿里源(安装jdk11、git测试)
CentOS Linux 8使用阿里源(安装jdk11、git测试)
94 1
|
24天前
|
Java 关系型数据库 MySQL
杨校老师课堂之Java项目部署到云端服务器之安装MySQL、Jdk、Tomcat
杨校老师课堂之Java项目部署到云端服务器之安装MySQL、Jdk、Tomcat
28 0
杨校老师课堂之Java项目部署到云端服务器之安装MySQL、Jdk、Tomcat
|
1月前
|
Oracle Java 关系型数据库
玩客云安装Armbian和部署jdk环境
该文介绍了在玩客云设备上安装Armbian系统和Java SDK的步骤。首先,需要准备玩客云设备、Armbian镜像文件和USB工具。然后,通过短接点刷入Armbian系统,并通过SSH访问。接着,从可信源下载Java SDK,将其解压并移动到合适目录,编辑环境变量使其生效。最后验证Java安装成功。注意选择兼容版本并备份数据。内容涵盖了ROM开发相关技术。

推荐镜像

更多