性能文章>分享一个新出炉的JVM里不痛不痒的BUG(Attach机制相关)>

分享一个新出炉的JVM里不痛不痒的BUG(Attach机制相关)原创

2年前
7503212

概述

老早之前写过一篇文章,关于attach机制的,可以看下这篇老文章了解一下JVM源码分析之Attach机制实现完全解读,比如大家常用的jstack,jmap等工具的主要原理都和attach机制有关,在JVM里处理这些命令的线程主要是Attach Listener这个线程,这个线程在JVM里是唯一的,我之前也一直以为是唯一的,但是我们同事最近在做一个线程分析产品的时候,发现我们抓到了多个Attach Listener线程,这让我也很疑惑,我第一感觉是不可能,肯定是数据抓错了,直到亲眼看到了两个同名的Attach Listener线程我才不得不相信原来还真有这种情况。

image.png

问题分析

不过从Attach Listener的实现来看,它设计的初衷不应该是一个多线程的设计,于是我昨晚上又翻了一遍代码,发现还真可能存在这种情况。举个栗子,当我们很多人同时执行jstack的时候,就可能会发生,当然有个前提是之前都没有做过任何和attach相关的操作。

Attach Listener线程默认情况下不会在JVM启动的时候就创建,当然也有一个JVM参数可以指定在JVM启动的时候就启动这个线程,这个就不会存在我们今天讨论的这个问题了,这个JVM参数是-XX:+StartAttachListener

当我们在运行时触发attach机制的时候,首先会通过Signal Dispatcher线程来创建Attach Listener线程,代码如下:

image.png

image.png

在上面的圈起来的init方法里会创建Attach Listener线程,但是在init方法执行之前会通过_initialized属性来判断是否需要创建线程,而_initialized设置为true是在attach_listener_thread_entry里,这个是Attach Listener Thread的entry,也就是当这个线程执行的时候执行的方法。

image.png

但是在设置_initialized=true之前,如果有多个请求信号发出了(比如同时又很多jstack命令触发),可能会创建多个Attach Listener,因为Signal DispatcherAttach Listener线程是异步执行的。

问题复现

为了让效果更明显,我们可以在hotspot里修改下代码重新编译下再跑demo

image.png

在上面函数里加上圈起来的这段代码,表示在设置_initialized属性之前停留15s,当进程起来之后,不断执行jstack <pid>,最终将会看到有非常多的Attach Listener线程

image.png

其实问题的根本就是有一个空档期(设置_initialized为true之前)可能存在多次创建线程的可能。

总结

总的来说,创建Attach Listener线程是通过Signal Dispatcher线程来创建的,但是决定Signal Dispatcher是否可以重复创建Attach Listener线程的标记是在某个Attach Listener线程里设置的,如果没有及时设置该标记,就可能存在创建多个Attach Listener线程的情况。

点赞收藏
分类:标签:
你假笨

通过创新的技术肯定可以让这个世界变得更美好,让我们为技术而狂吧

请先登录,查看2条精彩评论吧
快去登录吧,你将获得
  • 浏览更多精彩评论
  • 和开发者讨论交流,共同进步

为你推荐

JVM 常见线上问题:CPU100%、内存泄露的问题排查

JVM 常见线上问题:CPU100%、内存泄露的问题排查

【译】记一次数据库连接泄漏导致的响应迟缓

【译】记一次数据库连接泄漏导致的响应迟缓

【全网首发】微服务10:系统服务熔断、限流

【全网首发】微服务10:系统服务熔断、限流

【全网首发】MQ-消息堆积-JDK Bug导致线程阻塞案例分析

【全网首发】MQ-消息堆积-JDK Bug导致线程阻塞案例分析

FullGC没及时处理,差点造成P0事故

FullGC没及时处理,差点造成P0事故

【全网首发】一次想不到的 Bootstrap 类加载器带来的 Native 内存泄露分析

【全网首发】一次想不到的 Bootstrap 类加载器带来的 Native 内存泄露分析

12
2