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

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

目录
相关文章
|
19天前
|
安全 Java 编译器
一个 Bug JDK 居然改了十年?
你敢相信么一个简单的Bug,JDK 居然花了十年时间才修改完成。赶快来看看到底是个什么样的 Bug?
28 1
一个 Bug JDK 居然改了十年?
|
23天前
|
Java 编译器 API
深入解析:JDK与JVM的区别及联系
在Java开发和运行环境中,JDK(Java Development Kit)和JVM(Java Virtual Machine)是两个核心概念,它们在Java程序的开发、编译和运行过程中扮演着不同的角色。本文将深入解析JDK与JVM的区别及其内在联系,为Java开发者提供清晰的技术干货。
24 1
|
27天前
|
存储 机器学习/深度学习 编解码
阿里云服务器计算型c8i实例解析:实例规格性能及使用场景和最新价格参考
计算型c8i实例作为阿里云服务器家族中的重要成员,以其卓越的计算性能、稳定的算力输出、强劲的I/O引擎以及芯片级的安全加固,广泛适用于机器学习推理、数据分析、批量计算、视频编码、游戏服务器前端、高性能科学和工程应用以及Web前端服务器等多种场景。本文将全面介绍阿里云服务器计算型c8i实例,从规格族特性、适用场景、详细规格指标、性能优势、实际应用案例,到最新的活动价格,以供大家参考。
|
1月前
|
安全 Java 开发者
AOP中的JDK动态代理与CGLIB动态代理:深度解析与实战模拟
【11月更文挑战第21天】面向切面编程(AOP,Aspect-Oriented Programming)是一种编程范式,它通过将横切关注点(cross-cutting concerns)与业务逻辑分离,以提高代码的可维护性和可重用性。在Java开发中,AOP的实现离不开动态代理技术,其中JDK动态代理和CGLIB动态代理是两种常用的方式。本文将从背景、历史、功能点、业务场景、底层逻辑等多个维度,深度解析这两种代理方式的区别,并通过Java示例进行模拟和比较。
45 4
|
1月前
|
SQL IDE 数据库连接
IntelliJ IDEA处理大文件SQL:性能优势解析
在数据库开发和管理工作中,执行大型SQL文件是一个常见的任务。传统的数据库管理工具如Navicat在处理大型SQL文件时可能会遇到性能瓶颈。而IntelliJ IDEA,作为一个强大的集成开发环境,提供了一些高级功能,使其在执行大文件SQL时表现出色。本文将探讨IntelliJ IDEA在处理大文件SQL时的性能优势,并与Navicat进行比较。
32 4
|
1月前
|
监控 数据挖掘 OLAP
深入解析:AnalyticDB中的高级查询优化与性能调优
【10月更文挑战第22天】 AnalyticDB(ADB)是阿里云推出的一款实时OLAP数据库服务,它能够处理大规模的数据分析任务,提供亚秒级的查询响应时间。对于已经熟悉AnalyticDB基本操作的用户来说,如何通过查询优化和性能调优来提高数据处理效率,是进一步提升系统性能的关键。本文将从个人的角度出发,结合实际经验,深入探讨AnalyticDB中的高级查询优化与性能调优技巧。
102 4
|
2月前
|
Java 关系型数据库 MySQL
【编程基础知识】Eclipse连接MySQL 8.0时的JDK版本和驱动问题全解析
本文详细解析了在使用Eclipse连接MySQL 8.0时常见的JDK版本不兼容、驱动类错误和时区设置问题,并提供了清晰的解决方案。通过正确配置JDK版本、选择合适的驱动类和设置时区,确保Java应用能够顺利连接MySQL 8.0。
255 1
|
3月前
|
Java
安装JDK18没有JRE环境的解决办法
安装JDK18没有JRE环境的解决办法
378 3
|
4月前
|
Oracle Java 关系型数据库
Mac安装JDK1.8
Mac安装JDK1.8
770 4
|
4月前
|
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应用打下基础。
64 1

推荐镜像

更多
下一篇
DataWorks