分享一個新出爐的JVM裡不痛不癢的BUG(Attach機制相關)

PerfMa發表於2020-06-04

本文來自: PerfMa技術社群

PerfMa(笨馬網路)官網

概述

老早之前寫過一篇文章,關於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執行緒的情況。

 

一起來學習吧:

PerfMa KO 系列課之 JVM 引數【Memory篇】

實戰:一次疑似記憶體洩漏的問題排查

相關文章