JVM08-虛擬機故障處理之可視化故障處理工具JConsole工具

      網友投稿 837 2022-05-29

      前言

      上一篇我們介紹了JVM07-虛擬機故障處理命令行工具。這一篇將繼續介紹虛擬機故障處理之可視化故障處理工具JConsole工具。這個工具我們可以在JDK的bin目錄下找到。

      JConsole的介紹

      JConsole是一款基于JMX(Java Management Extensions)的可視化監視、管理工具。它主要是通過JMX的MBean對系統進行信息收集和參數動態調整。JMX是一種開放性的技術,不僅可以用在虛擬機本身的管理上,還可以運行于虛擬機之上的軟件中,典型的如中間件大多也是基于JMX來實現管理和監控的。

      JConsole的使用

      1. 啟動JConsole

      運行JDK/bin目錄下的jconsole.exe就可以啟動JConsole。JConsole啟動之后會自動搜索出本機運行的所有虛擬機進程(只能監控運行在本虛擬機的進程),而不需要用戶自己使用jps來查詢,如圖,有如下進程,雙擊選中JConsoleTest進程其中一個進程便可以進入主界面開始監控JConsoleTest進程的相關信息。同時JMX支持跨服務器的管理。

      內存監控

      "內存"頁簽的作用相當于可視化的jstat命令,用于監控被收集器管理的虛擬機內存(被收集器直接管理Java堆和被間接管理的方法區)的變化趨勢。如下 JConsoleTest類循環創建OOMObject對象,每隔50ms創建一個,就相當于以 100KB/50ms的速度向Java堆中填充數據。一共填充1000次。我們可以進入內存 頁簽中觀察內存變化趨勢。

      運行前的內存設置如下:設置堆內存最大為100m。

      -Xms100m -Xmx100m -XX:+UseSerialGC

      1

      上面我們只是指定了整個堆的內存,沒有指定新生代的大小。那么整個新生代的堆內存大小是多少呢?看下圖:

      如上圖,我們看到Eden區域的內存一直在平穩的增加,直到執行System.gc();之后才下降下來。

      看左下角可以知道Eden區域的大小是27,328 KB,同時沒有設置-XX:SurvivorRation,按照JVM默認的設置Eden與Survivor的比例為8:1,而新生代有兩個Survivor區域。所以整個新生代的內存大小是27328KB*1.25=34160KB。

      同時我們注意到在循環填充完數據之后,執行System.gc();之后,新生代的Eden和Survivor區域已使用內存明顯下降,但是老年代的內存還處于高位,這是為啥呢?這是因為System.gc();是放在setOOMObject方法內部調用的,而在該方法內oomObjectList對象還是有效的,是不能被回收的。所以老年代還是處于高位。要是oomObjectList對象也能被回收,只需要將System.gc();的調用放到setOOMObject方法外部調用。這樣才能使垃圾收集器可以收集老年代中的oomObjectList對象。

      public class JConsoleTest { public static void main(String[] args) throws InterruptedException { setOOMObject(1000); } /** * 內存占位符對象,一個OOMObject大約占100KB。 */ static class OOMObject{ private static final byte[] param = new byte[100 * 1024]; } public static void setOOMObject(int num) throws InterruptedException { List oomObjectList = new ArrayList<>(); Thread.sleep(3000); for (int i = 0; i < num; i++) { System.out.println("*********第["+i+"]次設值"); //休息50毫秒 Thread.sleep(50); oomObjectList.add(new OOMObject()); } System.gc(); } }

      JVM08-虛擬機故障處理之可視化故障處理工具JConsole工具

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      線程監控

      說完了內存監控,我們接著來看看線程監控,如果說JConsole的"內存"頁簽相當于可視化的jstat命令的話,那"線程"頁簽的功能就相當于可視化的jstack命令了,遇到線程停頓的時候可以使用這個頁簽的功能進行分析。我們知道線程長時間停頓的主要原因有等待外部資源(數據庫連接、網絡資源、設備資源等)、死循環、鎖等待等。下面用MonitoringTest類來模擬下等待外部資源、 死循環等待和鎖等待等情況。

      public class MonitoringTest { /** * 線程死循環演示 */ public static void createBusyThread() { new Thread(() -> { while (true) { } }, "testBusyThread").start(); } /** * 線程鎖等待演示 * @param lock */ public static void createLockThread(final Object lock) { new Thread(() -> { synchronized (lock) { try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } }, "testLockThread").start(); } public static void main(String[] args) throws IOException { //等待外部資源 BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in)); bufferedReader.readLine(); createBusyThread(); bufferedReader.readLine(); Object obj = new Object(); createLockThread(obj); } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      運行MonitoringTest之后,在JConsole中觀察其運行情況,首先我們在"線程"頁簽中選中main線程、堆棧追蹤顯示BufferedReader的readBytes()方法正在等待System.in的鍵盤輸入。這時候線程為Runnable狀態,Runnable狀態的線程仍會被分配運行時間,但readBytes()方法檢查到流沒有更新就會立即歸還令牌給操作系統,這種等待只消耗很小的處理器資源。如下圖所示:

      接著監控testBusyThread線程,如下圖所示:testBusyThread線程一直在執行空循環,從堆棧追蹤可以看到在MonitoringTest代碼的第17行停留,第17行的代碼為while(true)。這時候線程為Runable狀態,而且沒有歸還線程執行令牌的動作,所以會空循環耗盡系統分配給它的執行時間,直到線程切換為止,這種等待會消耗大量的處理器資源。

      最后我們看看testLockThread線程在等待lock對象的notify()或者notifyAll()方法的出現,線程這時候處于WAITING狀態,在重新喚醒之前不會被分配執行時間。同時會釋放占用的鎖對象。testLockThread線程正處于正常的活鎖等待中,只要lock對象的notify()或notifyAll()方法被調用,這個線程便能激活繼續執行。相關監控結果如下圖所示:

      說完了活鎖的情況,下面我們來看一個死鎖的情況。如下JConsoleDeadLockTest類,在Runable的run方法中加了兩把鎖(synchronized),鎖對象分別是 Integer.valueOf(a)和Integer.valueOf(b)。在main方法中定義兩個線程,傳入的a,b值相反。這種情況下就會出現死鎖,原因是Integer.valueOf()方法處于減少對象創建次數和節省內存的考慮,會對數值為-128~127之間的Integer對象進行緩存,如果valueOf()方法傳入的參數在這個范圍內,就直接返回緩存中的對象。也就是說盡管調用了100次Integer.valueOf()方法,但一共只返回了兩個不同的Integer對象,假如某個線程在兩個synchronized塊之間發生了一次線程切換,那就會出現線程A在等待了線程B持有的Integer.valueOf(1),而線程B又在等待線程A持有的Integer.valueOf(2),結果就發生了死鎖。

      public class JConsoleDeadLockTest { static class SyncAddRunner implements Runnable { int a, b; public SyncAddRunner(int a, int b) { this.a = a; this.b = b; } @Override public void run() { synchronized (Integer.valueOf(a)) { synchronized (Integer.valueOf(b)) { System.out.println(a + b); } } } } public static void main(String[] args) { for (int i = 0; i < 100; i++) { new Thread(new SyncAddRunner(1, 2),"線程一").start(); new Thread(new SyncAddRunner(2, 1), "線程二").start(); } } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      我們接著看下在 JConsole中的監控情況。同樣的選中線程 頁簽,然后,點擊檢查死鎖 按鈕,就可以看到 線程一和線程二發生了死鎖。

      總結

      本文主要介紹了JConsole工具的使用場景,以及使用方法。JConsole是JDK自帶的可視化監控工具,在實際的工作中我們可以用它來分析系統的運行狀況。

      參考

      深入理解Java虛擬機(第3版)

      Java JDK JVM 虛擬化

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:Linux學習筆記Day5之Linux服務管理
      下一篇:Python—OpenCV創建級聯文件(Windows7/10環境)
      相關文章
      伊人亚洲综合青草青草久热| 亚洲综合无码一区二区| 亚洲AV无码不卡在线播放| 亚洲 无码 在线 专区| 亚洲日韩精品无码AV海量| 亚洲男人电影天堂| 久久久久亚洲av无码专区导航| 亚洲开心婷婷中文字幕| 国产午夜亚洲精品午夜鲁丝片| 亚洲av手机在线观看| 亚洲a无码综合a国产av中文| 亚洲久热无码av中文字幕| 亚洲日本天堂在线| 一区二区亚洲精品精华液| 亚洲人成网站在线在线观看| 亚洲精品美女久久久久久久| 久久亚洲AV成人无码国产电影| MM1313亚洲国产精品| 国产成人 亚洲欧洲| 亚洲精品99久久久久中文字幕| 国产精品亚洲视频| 亚洲综合区小说区激情区 | 曰韩亚洲av人人夜夜澡人人爽 | 国产V亚洲V天堂无码| 无码久久精品国产亚洲Av影片 | 亚洲A∨精品一区二区三区| 亚洲国产小视频精品久久久三级| 亚洲人成电影网站国产精品| 在线a亚洲v天堂网2019无码| 亚洲日本va在线视频观看| 亚洲国产精品久久久天堂| 亚洲一级二级三级不卡| 亚洲欧洲国产精品久久| 亚洲中文字幕无码中文| 国产偷国产偷亚洲清高APP| 精品国产亚洲男女在线线电影| 亚洲午夜福利AV一区二区无码| 亚洲精选在线观看| 精品久久亚洲中文无码| 亚洲AV性色在线观看| 国产精品亚洲mnbav网站 |