分享一個新出爐的JVM里不痛不癢的BUG(Attach機制相關)
- 2020 年 6 月 4 日
- 筆記
本文來自: PerfMa技術社區
概述
老早之前寫過一篇文章,關於attach機制的,可以看下這篇老文章了解一下JVM源碼分析之Attach機制實現完全解讀,比如大家常用的jstack,jmap等工具的主要原理都和attach機制有關,在JVM里處理這些命令的執行緒主要是Attach Listener
這個執行緒,這個執行緒在JVM里是唯一的,我之前也一直以為是唯一的,但是我們同事最近在做一個執行緒分析產品的時候,發現我們抓到了多個Attach Listener
執行緒,這讓我也很疑惑,我第一感覺是不可能,肯定是數據抓錯了,直到親眼看到了兩個同名的Attach Listener
執行緒我才不得不相信原來還真有這種情況。
問題分析
不過從Attach Listener
的實現來看,它設計的初衷不應該是一個多執行緒的設計,於是我昨晚上又翻了一遍程式碼,發現還真可能存在這種情況。舉個栗子,當我們很多人同時執行jstack的時候,就可能會發生,當然有個前提是之前都沒有做過任何和attach相關的操作。
Attach Listener
執行緒默認情況下不會在JVM啟動的時候就創建,當然也有一個JVM參數可以指定在JVM啟動的時候就啟動這個執行緒,這個就不會存在我們今天討論的這個問題了,這個JVM參數是-XX:+StartAttachListener
。
當我們在運行時觸發attach機制的時候,首先會通過Signal Dispatcher
執行緒來創建Attach Listener
執行緒,程式碼如下:
在上面的圈起來的init方法里會創建Attach Listener
執行緒,但是在init方法執行之前會通過_initialized
屬性來判斷是否需要創建執行緒,而_initialized
設置為true是在attach_listener_thread_entry
里,這個是Attach Listener Thread
的entry,也就是當這個執行緒執行的時候執行的方法。
但是在設置_initialized=true
之前,如果有多個請求訊號發出了(比如同時又很多jstack命令觸發),可能會創建多個Attach Listener
,因為Signal Dispatcher
和Attach Listener
執行緒是非同步執行的。
問題復現
為了讓效果更明顯,我們可以在hotspot里修改下程式碼重新編譯下再跑demo
在上面函數里加上圈起來的這段程式碼,表示在設置_initialized
屬性之前停留15s,當進程起來之後,不斷執行jstack <pid>
,最終將會看到有非常多的Attach Listener
執行緒
其實問題的根本就是有一個空檔期(設置_initialized
為true之前)可能存在多次創建執行緒的可能。
總結
總的來說,創建Attach Listener
執行緒是通過Signal Dispatcher
執行緒來創建的,但是決定Signal Dispatcher
是否可以重複創建Attach Listener
執行緒的標記是在某個Attach Listener
執行緒里設置的,如果沒有及時設置該標記,就可能存在創建多個Attach Listener
執行緒的情況。
一起來學習吧:
PerfMa KO 系列課之 JVM 參數【Memory篇】