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

本文來自: 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裏修改下代碼從新編譯下再跑demospa

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篇】

實戰:一次疑似內存泄漏的問題排查

相關文章
相關標籤/搜索