【Java開發日記】6個Java 工具,輕松分析定位 JVM 問題 !

目錄

使用 JDK 自帶工具查看 JVM 情況

jps

jinfo

jvisualvm

jcm


使用 JDK 自帶工具查看 JVM 情況

JDK 自帶了很多命令行甚至是圖形界面工具,幫助查看 JVM 的一些信息。比如,在機器上運行?ls?命令,可以看到 JDK 8 提供了非常多的工具或程序:
?

接下來介紹些常用的監控工具。也可以先通過下面這張圖了解下各種工具的基本作用:

為了測試這些工具,先來寫一段代碼:啟動 10 個死循環的線程,每個線程分配一個 10MB 左右的字符串,然后休眠 10 秒。可以想象到,這個程序會對 GC 造成壓力:

//啟動10個線程
IntStream.rangeClosed(1, 10).mapToObj(i -> new Thread(() -> {while (true) {//每一個線程都是一個死循環,休眠10秒,打印10M數據String payload = IntStream.rangeClosed(1, 10000000).mapToObj(__ -> "a").collect(Collectors.joining("")) + UUID.randomUUID().toString();try {TimeUnit.SECONDS.sleep(10);} catch (InterruptedException e) {e.printStackTrace();}System.out.println(payload.length());}
})).forEach(Thread::start);
TimeUnit.HOURS.sleep(1);

修改 pom.xml,配置 spring-boot-maven-plugin 插件打包的 Java 程序的 main 方法類:

<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>org.geekbang.time.commonmistakes.troubleshootingtools.jdktool.CommonMistakesApplication
</mainClass>
</configuration>
</plugin>

然后使用?java -jar?啟動進程,設置 JVM 參數,讓堆最小最大都是 1GB:

java -jar common-mistakes-0.0.1-SNAPSHOT.jar -Xms1g -Xmx1g

完成這些準備工作后,就可以使用 JDK 提供的工具,來觀察分析這個測試程序了。?

jps

首先,使用 jps 得到 Java 進程列表,這會比使用 ps 來的方便:

?  ~ jps
12707
22261 Launcher
23864 common-mistakes-0.0.1-SNAPSHOT.jar
15608 RemoteMavenServer36
23243 Main
23868 Jps
22893 KotlinCompileDaemon

jinfo

然后,可以使用 jinfo 打印 JVM 的各種參數:

?  ~ jinfo 23864
Java System Properties:
#Wed Jan 29 12:49:47 CST 2020
...
user.name=zhuye
path.separator=\:
os.version=10.15.2
java.runtime.name=Java(TM) SE Runtime Environment
file.encoding=UTF-8
java.vm.name=Java HotSpot(TM) 64-Bit Server VM
...
VM Flags:
-XX:CICompilerCount=4 -XX:ConcGCThreads=2 -XX:G1ConcRefinementThreads=8 -XX:G1HeapRegionSize=1048576 -XX:GCDrainStackTargetSize=64 -XX:InitialHeapSize=268435456 -XX:MarkStackSize=4194304 -XX:MaxHeapSize=4294967296 -XX:MaxNewSize=2576351232 -XX:MinHeapDeltaBytes=1048576 -XX:NonNMethodCodeHeapSize=5835340 -XX:NonProfiledCodeHeapSize=122911450 -XX:ProfiledCodeHeapSize=122911450 -XX:ReservedCodeCacheSize=251658240 -XX:+SegmentedCodeCache -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseG1GC
VM Arguments:
java_command: common-mistakes-0.0.1-SNAPSHOT.jar -Xms1g -Xmx1g
java_class_path (initial): common-mistakes-0.0.1-SNAPSHOT.jar
Launcher Type: SUN_STANDARD

查看第 15 行和 19 行可以發現,設置 JVM 參數的方式不對,**-Xms1g**?和?**-Xmx1g**?這兩個參數被當成了 Java 程序的啟動參數,整個 JVM 目前最大內存是 4GB 左右,而不是 1GB。
因此,當懷疑 JVM 的配置很不正常的時候,要第一時間使用工具來確認參數。除了使用工具確認 JVM 參數外,也可以打印 VM 參數和程序參數:

System.out.println("VM options");
System.out.println(ManagementFactory.getRuntimeMXBean().getInputArguments().stream().collect(Collectors.joining(System.lineSeparator())));
System.out.println("Program arguments");
System.out.println(Arrays.stream(args).collect(Collectors.joining(System.lineSeparator())));

把 JVM 參數放到 -jar 之前,重新啟動程序,可以看到如下輸出,從輸出也可以確認這次 JVM 參數的配置正確了:

?  target git:(master) ? java -Xms1g -Xmx1g -jar common-mistakes-0.0.1-SNAPSHOT.jar test
VM options
-Xms1g
-Xmx1g
Program arguments
test

jvisualvm

然后,啟動另一個重量級工具 jvisualvm 觀察一下程序,可以在概述面板再次確認 JVM 參數設置成功了:

繼續觀察監視面板可以看到,JVM 的 GC 活動基本是 10 秒發生一次,堆內存在 250MB 到 900MB 之間波動,活動線程數是 22。可以在監視面板看到 JVM 的基本情況,也可以直接在這里進行手動 GC 和堆 Dump 操作:

jconsole如果希望看到各個內存區的 GC 曲線圖,可以使用 jconsole 觀察。jconsole 也是一個綜合性圖形界面監控工具,比 jvisualvm 更方便的一點是,可以用曲線的形式監控各種數據,包括 MBean 中的屬性值:

?jstat

同樣,如果沒有條件使用圖形界面(畢竟在 Linux 服務器上,主要使用命令行工具),又希望看到 GC 趨勢的話,可以使用 jstat 工具。
jstat 工具允許以固定的監控頻次輸出 JVM 的各種監控指標,比如使用?-gcutil?輸出 GC 和內存占用匯總信息,每隔 5 秒輸出一次,輸出 100 次,可以看到 Young GC 比較頻繁,而 Full GC 基本 10 秒一次:

?  ~ jstat -gcutil 23940 5000 100S0     S1     E      O      M     CCS    YGC     YGCT    FGC    FGCT    CGC    CGCT     GCT0.00 100.00   0.36  87.63  94.30  81.06    539   14.021    33    3.972   837    0.976   18.9680.00 100.00   0.60  69.51  94.30  81.06    540   14.029    33    3.972   839    0.978   18.9790.00   0.00   0.50  99.81  94.27  81.03    548   14.143    34    4.002   840    0.981   19.1260.00 100.00   0.59  70.47  94.27  81.03    549   14.177    34    4.002   844    0.985   19.1640.00 100.00   0.57  99.85  94.32  81.09    550   14.204    34    4.002   845    0.990   19.1960.00 100.00   0.65  77.69  94.32  81.09    559   14.469    36    4.198   847    0.993   19.6590.00 100.00   0.65  77.69  94.32  81.09    559   14.469    36    4.198   847    0.993   19.6590.00 100.00   0.70  35.54  94.32  81.09    567   14.763    37    4.378   853    1.001   20.1420.00 100.00   0.70  41.22  94.32  81.09    567   14.763    37    4.378   853    1.001   20.1420.00 100.00   1.89  96.76  94.32  81.09    574   14.943    38    4.487   859    1.007   20.4380.00 100.00   1.39  39.20  94.32  81.09    575   14.946    38    4.487   861    1.010   20.442

其中,S0 表示 Survivor0 區占用百分比,S1 表示 Survivor1 區占用百分比,E 表示 Eden 區占用百分比,O 表示老年代占用百分比,M 表示元數據區占用百分比,YGC 表示年輕代回收次數,YGCT 表示年輕代回收耗時,FGC 表示老年代回收次數,FGCT 表示老年代回收耗時。
jstat 命令的參數眾多,包含?-class-compiler-gc?等。Java 8、Linux/Unix 平臺 jstat 工具的完整介紹,可以查看這里。jstat 定時輸出的特性,可以方便持續觀察程序的各項指標。
繼續來到線程面板可以看到,大量以 Thread 開頭的線程基本都是有節奏的 10 秒運行一下,其他時間都在休眠,和代碼邏輯匹配:

點擊面板的線程 Dump 按鈕,可以查看線程瞬時的線程棧:

?jstack

通過命令行工具 jstack,也可以實現抓取線程棧的操作:

?  ~ jstack 23940
2020-01-29 13:08:15
Full thread dump Java HotSpot(TM) 64-Bit Server VM (11.0.3+12-LTS mixed mode):
...
"main" #1 prio=5 os_prio=31 cpu=440.66ms elapsed=574.86s tid=0x00007ffdd9800000 nid=0x2803 waiting on condition  [0x0000700003849000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(java.base@11.0.3/Native Method)
at java.lang.Thread.sleep(java.base@11.0.3/Thread.java:339)
at java.util.concurrent.TimeUnit.sleep(java.base@11.0.3/TimeUnit.java:446)
at org.geekbang.time.commonmistakes.troubleshootingtools.jdktool.CommonMistakesApplication.main(CommonMistakesApplication.java:41)
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(java.base@11.0.3/Native Method)
at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(java.base@11.0.3/NativeMethodAccessorImpl.java:62)
at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(java.base@11.0.3/DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(java.base@11.0.3/Method.java:566)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:51)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:52)
"Thread-1" #13 prio=5 os_prio=31 cpu=17851.77ms elapsed=574.41s tid=0x00007ffdda029000 nid=0x9803 waiting on condition  [0x000070000539d000]
java.lang.Thread.State: TIMED_WAITING (sleeping)
at java.lang.Thread.sleep(java.base@11.0.3/Native Method)
at java.lang.Thread.sleep(java.base@11.0.3/Thread.java:339)
at java.util.concurrent.TimeUnit.sleep(java.base@11.0.3/TimeUnit.java:446)
at org.geekbang.time.commonmistakes.troubleshootingtools.jdktool.CommonMistakesApplication.lambda$null$1(CommonMistakesApplication.java:33)
at org.geekbang.time.commonmistakes.troubleshootingtools.jdktool.CommonMistakesApplication$$Lambda$41/0x00000008000a8c40.run(Unknown Source)
at java.lang.Thread.run(java.base@11.0.3/Thread.java:834)
...

抓取后可以使用類似fastthread(https://fastthread.io/)這樣的在線分析工具來分析線程棧。?

jcmd

最后,來看一下 Java HotSpot 虛擬機的 NMT 功能。
通過 NMT,可以觀察細粒度內存使用情況,設置?-XX:NativeMemoryTracking=summary/detail?可以開啟 NMT 功能,開啟后可以使用 jcmd 工具查看 NMT 數據。
重新啟動一次程序,這次加上 JVM 參數以 detail 方式開啟 NMT:

-Xms1g -Xmx1g -XX:ThreadStackSize=256k -XX:NativeMemoryTracking=detail

在這里,還增加了?-XX:ThreadStackSize?參數,并將其值設置為 256k,也就是期望把線程棧設置為 256KB。通過 NMT 觀察一下設置是否成功。
啟動程序后執行如下 jcmd 命令,以概要形式輸出 NMT 結果。可以看到,當前有 32 個線程,線程棧總共保留了差不多 4GB 左右的內存。明明配置線程棧最大 256KB,為什么會出現 4GB 這么夸張的數字呢,到底哪里出了問題呢?

?  ~ jcmd 24404 VM.native_memory summary
24404:
Native Memory Tracking:
Total: reserved=6635310KB, committed=5337110KB
-                 Java Heap (reserved=1048576KB, committed=1048576KB)(mmap: reserved=1048576KB, committed=1048576KB)
-                     Class (reserved=1066233KB, committed=15097KB)(classes #902)(malloc=9465KB #908)(mmap: reserved=1056768KB, committed=5632KB)
-                    Thread (reserved=4209797KB, committed=4209797KB)(thread #32)(stack: reserved=4209664KB, committed=4209664KB)(malloc=96KB #165)(arena=37KB #59)
-                      Code (reserved=249823KB, committed=2759KB)(malloc=223KB #730)(mmap: reserved=249600KB, committed=2536KB)
-                        GC (reserved=48700KB, committed=48700KB)(malloc=10384KB #135)(mmap: reserved=38316KB, committed=38316KB)
-                  Compiler (reserved=186KB, committed=186KB)(malloc=56KB #105)(arena=131KB #7)
-                  Internal (reserved=9693KB, committed=9693KB)(malloc=9661KB #2585)(mmap: reserved=32KB, committed=32KB)
-                    Symbol (reserved=2021KB, committed=2021KB)(malloc=1182KB #334)(arena=839KB #1)
-    Native Memory Tracking (reserved=85KB, committed=85KB)(malloc=5KB #53)(tracking overhead=80KB)
-               Arena Chunk (reserved=196KB, committed=196KB)(malloc=196KB)

重新以?VM.native_memory detail?參數運行 jcmd:

jcmd 24404 VM.native_memory detail

可以看到,有 16 個可疑線程,每一個線程保留了 262144KB 內存,也就是 256MB(通過下圖紅框可以看到,使用關鍵字 262144KB for Thread Stack from 搜索到了 16 個結果):

其實,ThreadStackSize 參數的單位是 KB,所以如果要設置線程棧 256KB,那么應該設置 256 而不是 256k。重新設置正確的參數后,使用 jcmd 再次驗證下:

除了用于查看 NMT 外,jcmd 還有許多功能。可以通過 help,看到它的所有功能:

jcmd 24781 help

除了 jps、jinfo、jcmd、jstack、jstat、jconsole、jvisualvm 外,JDK 中還有一些工具,可以通過官方文檔查看完整介紹。

官方文檔:https://docs.oracle.com/javase/8/docs/technotes/tools/

?如果小假的內容對你有幫助,請點贊評論收藏。創作不易,大家的支持就是我堅持下去的動力!

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/78015.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/78015.shtml
英文地址,請注明出處:http://en.pswp.cn/web/78015.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

動態規劃簡單題2

leetcode91題&#xff08;解碼方法&#xff09; 分析題目&#xff1a; 1.這是一種解碼&#xff0c;就是給多個數字組成的字符串&#xff0c;把這些數字解碼成字母&#xff0c;看看一共有多少種 2.如果一個數字前有前導0就不合法&#xff0c;比如06&#xff0c;這與6不同&…

(007)Excel 公式的使用

文章目錄 邏輯運算公式的參數常用函數引用方式引用工作表和工作簿表格的引用修改公式的計算時機區域交叉引用 邏輯運算 公式的參數 單元格引用&#xff1a;SUM(A1:A24)。字面值&#xff1a;SQRT(121)。字面文本字符串&#xff1a;PROPER(“john.f.smith”)。表達式&#xff1a…

Unity 和 Unreal Engine(UE) 兩大主流游戲引擎的核心使用方法

以下是 Unity 和 Unreal Engine&#xff08;UE&#xff09; 兩大主流游戲引擎的核心使用方法和對比分析&#xff0c;幫助開發者快速上手并根據項目需求選擇合適工具&#xff1a; 一、Unity 使用指南 1. 安裝與配置 安裝&#xff1a;從 Unity Hub 下載&#xff0c;選擇長期支持…

猜數字游戲:從數學原理到交互體驗的完整設計指南

目錄 猜數字游戲&#xff1a;從數學原理到交互體驗的完整設計指南引言第一章 游戲數學原理1.1 均勻分布與隨機生成1.2 最優猜測策略 第二章 游戲系統設計2.1 核心架構2.2 動態難度系統 第三章 交互設計細節3.1 輸入驗證系統3.2 漸進式提示機制 第四章 進階功能設計4.1 智能輔導…

2025工業大模型白皮書 | 螞蟻工廠北京航空航天大學聯合出品

由螞蟻工廠與北京航空航天大學聯合發布的《2025工業大模型白皮書》是一部針對工業領域大模型技術發展的前瞻性研究報告。該白皮書系統梳理了工業大模型的技術演進、核心應用場景、關鍵挑戰及未來發展趨勢&#xff0c;旨在為制造業數字化轉型提供理論支撐和實踐指南。作為產學研…

JavaWeb:后端web基礎(TomcatServletHTTP)

一、今日內容 二、Tomcat 介紹與使用 介紹 基本使用 小結 配置 配置 查找進程 三、Servlet 什么是Servlet 快速入門 需求 步驟 1.新建工程-模塊&#xff08;Maven&#xff09; 2.修改打包方式-war 3.編寫代碼 /*** 可以選擇繼承HttpServlet*/ WebServlet("/hello&q…

構建現代分布式云架構的三大支柱:服務化、Service Mesh 與 Serverless

目錄 前言1. 服務化架構模式&#xff1a;構建可擴展的基礎單元1.1 服務化的定義與演進1.2 在分布式云中的價值1.3 面臨的挑戰 2. Service Mesh 架構&#xff1a;服務通信的治理中樞2.1 什么是 Service Mesh&#xff1f;2.2 功能與優勢2.3 在分布式云中的角色2.4 落地難點 3. Se…

嵌入式C語言的運算符與輸入輸出

目錄 1. 運算符 1.1 位運算符 1.1.1 位運算 ~ 1.1.2 位邏輯與 & 1.1.3 位邏輯或 | 1.1.4 位邏輯異或 ^ 1.1.5 位移位運算 1.1.6 將無符號位的某位快速置 1 1.2 三目運算符 1.3 逗號運算符 1.4 運算符優先級 2. 輸出 2.1 字符輸出函數 2.2 格式輸出函數 2.3 字符…

IPD研學:76頁頁基于IPD思想-華為需求管理培訓方案【附全文閱讀】

適應人群 本方案適用于企業中參與產品研發、市場、銷售、項目管理等部門的人員,尤其是負責需求管理工作的相關從業者;致力于提升產品競爭力,對優化需求管理流程、提高產品開發質量感興趣的企業管理者;以及希望了解行業前沿需求管理方法,尋求突破和創新的相關人士。…

米酒的功能和優缺點

米酒&#xff08;又稱甜酒、酒釀&#xff09;是一種以糯米或其他谷物為原料&#xff0c;經發酵制成的傳統發酵飲品&#xff0c;酒精度較低&#xff08;通常1%-10%&#xff09;。以下是其功能、優點及缺點分析&#xff1a; 一、米酒的功能 營養補充 富含B族維生素&#xff08;B1…

注冊登錄頁面項目

關系型數據庫地址&#xff1a;C:\Users\ASUS\AppData\Local\Temp\HuaweiDevEcoStudioDatabases\rdb #注冊頁面register.ets import dataRdb from ohos.data.rdbconst STORE_CONFIG {name: weather4.db } const TABLE_NAME weather_info const SQL_CREATE_TABLE CREATE TAB…

yum源配置文件CentOS-Base.repo完整內容

1.CentOS Yum 源配置文件 CentOS-Base.repo 的完整內容示例&#xff1a; 以下是適用于不同版本 CentOS 系統的 CentOS-Base.repo 文件的標準模板。這些模板基于常見的國內鏡像源&#xff08;如阿里云、清華大學等&#xff09;&#xff0c;可以幫助解決倉庫配置失敗的問題。 適…

深度學習基礎--目標檢測入門簡介

博主簡介&#xff1a;努力學習的22級本科生一枚 &#x1f31f;? 博客主頁&#xff1a;羊小豬~~-CSDN博客 內容簡介&#xff1a;探索AI算法&#xff0c;C&#xff0c;go語言的世界&#xff1b;在迷茫中尋找光芒?&#x1f338;? 往期回顧&#xff1a;yolov5基礎–一步一步教…

雅思寫作--70個高頻表達

文章目錄 1. learn new skills學生通過戶外活動學到很多新技2. take immediate action to do各國采取有效行動以保護環境政府采取了必要行動以減少失業。你應該立即采取行動來解3. communication skills4. grow significantly5. have many advantages1. learn new skills “lea…

深入理解虛擬機與容器:原理、對比與應用場景分析

目錄 前言1 虛擬機技術詳解1.1 虛擬機的基本原理1.2 虛擬機的優勢與局限 2 容器技術詳解2.1 容器的運行機制2.2 容器的優勢與局限 3 虛擬機與容器的核心差異對比3.1 架構對比3.2 啟動速度與資源消耗3.3 安全性與隔離性3.4 兼容性與遷移性 4 實際應用場景分析4.1 適合使用虛擬機…

SQL Server數據庫提權的幾種方法——提權教程

SQL Server數據庫提權的幾種方法——提權教程 一、簡介 在利用系統溢出漏洞沒有效果的情況下,可以采用數據庫進行提權。 數據庫提權的前提條件: 1、服務器開啟數據庫服務 2、獲取到最高權限用戶密碼 (除Access數據庫外,其他數據庫基本都存在數據庫提權的可能) 二、使用x…

【第19節 信息加解密技術】

本章目錄: 一、節概述二、知識詳解1. 信息加密的基本分類2. 對稱加密算法詳解3. 非對稱加密算法詳解4. 密鑰控制技術5. 密鑰分發機制6. 公鑰體系的密鑰管理機制7. 密鑰分類與生成 三、關鍵點提煉四、考試提示五、總結與建議 一、節概述 在信息安全體系中&#xff0c;信息加解密…

記錄搭建自己的應用中心-需求看板搭建

記錄搭建自己的應用中心-需求看板搭建 人員管理新增用戶組織用戶登錄和操作看板狀態看板任務通知任務詳情 人員管理 由于不是所有人都有應用管理權限&#xff0c;所以額外做了一套應用登錄權限&#xff0c;做了一個新的組織人員表&#xff0c;一個登錄賬戶下的所有應用人員共享…

Java從入門到精通 - Java入門

Java 入門 此筆記參考黑馬教程&#xff0c;僅學習使用&#xff0c;如有侵權&#xff0c;聯系必刪 文章目錄 Java 入門01 Java快速入門1. Java 是什么&#xff1f;能干什么&#xff1f;1.1 Java 背景知識1.2 Java 能做什么&#xff1f;1.3 Java 技術體系 2. 如何使用 Java&…

MySQL-排序

介紹 在MySQL中&#xff0c;排序查詢結果可以使用 ORDER BY 子句來實現。這個子句允許你根據一個或多個列進行排序&#xff0c;并且可以選擇升序&#xff08;ASC&#xff09;或者降序&#xff08;DESC&#xff09;的方式。以下是基本的語法結構&#xff1a; SELECT column1, …