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

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 当然这个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讨论的邮件列表

目录
相关文章
|
20天前
|
监控 数据挖掘 OLAP
深入解析:AnalyticDB中的高级查询优化与性能调优
【10月更文挑战第22天】 AnalyticDB(ADB)是阿里云推出的一款实时OLAP数据库服务,它能够处理大规模的数据分析任务,提供亚秒级的查询响应时间。对于已经熟悉AnalyticDB基本操作的用户来说,如何通过查询优化和性能调优来提高数据处理效率,是进一步提升系统性能的关键。本文将从个人的角度出发,结合实际经验,深入探讨AnalyticDB中的高级查询优化与性能调优技巧。
59 4
|
1月前
|
Java 关系型数据库 MySQL
【编程基础知识】Eclipse连接MySQL 8.0时的JDK版本和驱动问题全解析
本文详细解析了在使用Eclipse连接MySQL 8.0时常见的JDK版本不兼容、驱动类错误和时区设置问题,并提供了清晰的解决方案。通过正确配置JDK版本、选择合适的驱动类和设置时区,确保Java应用能够顺利连接MySQL 8.0。
130 1
|
1月前
|
存储 缓存 监控
深入解析:Elasticsearch集群性能调优策略与最佳实践
【10月更文挑战第8天】Elasticsearch 是一个分布式的、基于 RESTful 风格的搜索和数据分析引擎,它能够快速地存储、搜索和分析大量数据。随着企业对实时数据处理需求的增长,Elasticsearch 被广泛应用于日志分析、全文搜索、安全信息和事件管理(SIEM)等领域。然而,为了确保 Elasticsearch 集群能够高效运行并满足业务需求,需要进行一系列的性能调优工作。
79 3
|
1月前
|
存储 数据处理 Python
深入解析Python中的生成器:效率与性能的双重提升
生成器不仅是Python中的一个高级特性,它们是构建高效、内存友好型应用程序的基石。本文将深入探讨生成器的内部机制,揭示它们如何通过惰性计算和迭代器协议提高数据处理的效率。
|
1月前
|
搜索推荐 Shell
解析排序算法:十大排序方法的工作原理与性能比较
解析排序算法:十大排序方法的工作原理与性能比较
49 9
|
2月前
|
缓存 Java 应用服务中间件
Java虚拟线程探究与性能解析
本文主要介绍了阿里云在Java-虚拟-线程任务中的新进展和技术细节。
|
1月前
|
缓存 Java 索引
查看并解析当前jdk的垃圾收集器
本文介绍了如何查看和解析当前JDK使用的垃圾收集器,通过在IDEA中配置JVM选项并运行示例代码来展示G1垃圾回收器的详细信息和命令行标志。
23 0
查看并解析当前jdk的垃圾收集器
|
2月前
|
物联网 5G UED
深入解析载波聚合及其对无线通信性能的提升
深入解析载波聚合及其对无线通信性能的提升
91 1
|
2月前
|
Java
安装JDK18没有JRE环境的解决办法
安装JDK18没有JRE环境的解决办法
313 3
|
3月前
|
Java 关系型数据库 MySQL
"解锁Java Web传奇之旅:从JDK1.8到Tomcat,再到MariaDB,一场跨越数据库的冒险安装盛宴,挑战你的技术极限!"
【8月更文挑战第19天】在Linux上搭建Java Web应用环境,需安装JDK 1.8、Tomcat及MariaDB。本指南详述了使用apt-get安装OpenJDK 1.8的方法,并验证其版本。接着下载与解压Tomcat至`/usr/local/`目录,并启动服务。最后,通过apt-get安装MariaDB,设置基本安全配置。完成这些步骤后,即可验证各组件的状态,为部署Java Web应用打下基础。
57 1

推荐镜像

更多