总结
很久以前我写过一篇关于Attach机制的文章。您可以阅读这篇旧文章,了解JVM源代码分析中附加机制的完整解释。例如,jstack和jmap等常用工具的主要原理都与附加机制有关。在JVM中处理这些命令的线程主要是Attach Listener线程,这在JVM中是唯一的。之前一直以为是独一无二的,但是最近我们同事在做一个线程分析产品的时候,发现我们抓了几个Attach Listener线程,这让我很疑惑。我的第一感觉是不可能,数据肯定是被抓错了。直到亲眼看到两条同名的Attach Listener线程,我才不得不相信这是真的发生了。
这个问题是昨晚定位的,今天早上送到OpenJDK社区,很快就被社区里的BUG确认了。这是一个新的bug(关于BUG的细节,你可以点击原文阅读)。到目前为止,我们工厂已经向OpenJDK社区贡献了4个bug和Patch。如果你有这个兴趣,请联系我们(微信:PerfMa)为社区做一些力所能及的事情。
问题分析
但是根据Attach Listener的实现,它原来的设计应该不是多线程设计,所以我昨晚又翻了一遍代码,发现这个可能真的存在。例如,当我们许多人同时执行jstack时,它可能会发生。当然,有一个前提是,我们之前没有做过任何与附加相关的操作。
默认情况下,当JVM启动时,不会创建附加侦听器线程。当然,还有一个JVM参数可以指定在JVM启动时启动这个线程,所以我们今天讨论的问题就不存在了。JVM参数是-XX:+StartAttachListener。
当我们在运行时触发附加机制时,我们将首先通过信号调度器线程创建附加侦听器线程,代码如下:
在上面圈起来的init方法中会创建Attach Listener线程,但是在执行init方法之前,会通过_initialized属性判断是否需要创建一个线程,并且_initialized为true的设置是在attach_listener_thread_entry中,它是Attach Listener thread的条目,也就是执行这个线程时执行的方法。
但是,在set _ initialized = true之前,如果发送了多个请求信号(例如,同时触发了许多jstack命令),可能会创建多个附加侦听器,因为信号调度器和附加侦听器线程是异步执行的。
问题重现
为了让效果更明显,我们可以在运行demo之前修改hotspot中的代码并重新编译
上面函数中带圈的代码表示在设置_initialized属性前停留15s,进程启动后继续执行jstack
其实问题的根源是有一个空文件周期(在set _ initialized为true之前),可能有多次创建线程的可能。
总结
一般来说,连接侦听器线程是由信号调度器线程创建的,但是决定信号调度器是否可以重复创建连接侦听器线程的标志是在连接侦听器线程中设置的。如果未及时设置该标志,可能会出现创建多个连接侦听器线程的情况。
欢迎关注个人微信微信官方账号,主要围绕JVM写一系列原理和性能调优的文章,也关注我们公司的微信官方账号
1.《attach 假笨说-分享一个新出炉的JVM里不痛不痒的BUG》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。
2.《attach 假笨说-分享一个新出炉的JVM里不痛不痒的BUG》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。
3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/yule/873288.html