jmap命令詳解:內存分析利器

一、jmap介紹

jmap是JDK自帶的一款用於獲取Java應用的heap或類信息快照的命令行工具,它能夠讓我們更好地了解內存中對象的使用情況,從而方便優化應用程序。

二、jmap常用選項

jmap有多個選項,我們通常會用到以下幾個:

-heap

該選項可以讓我們獲得應用程序的heap大小、佔用率等內存信息。例如:

jmap -heap 19321

這條命令會輸出進程號19321對應的Java應用的heap信息,例如:

Attaching to process ID 19321, please wait...
Debugger attached successfully.
Server compiler detected
JVM version is 25.102-b14
using thread-local object allocation.
Parallel GC with 4 thread(s)

Heap Configuration:
   MinHeapFreeRatio = 40
   MaxHeapFreeRatio = 70
   MaxHeapSize      = 2147483648 (2048.0MB)  // 最大可用heap大小
   NewSize          = 1048576 (1.0MB)        // 新生代大小
   MaxNewSize       = 33554432 (32.0MB)      // 新生代最大大小
   OldSize          = 4194304 (4.0MB)        // 老年代大小
   NewRatio         = 2
   SurvivorRatio    = 8
   MetaspaceSize    = 21807104 (20.796875MB)  //永久代大小
   CompressedClassSpaceSize = 1073741824 (1024.0MB)  //壓縮類空間大小
   MaxMetaspaceSize = 17592186044415 MB
   G1HeapRegionSize = 0 (0.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 279183360 (266.125MB)  // Eden區域容量
   used     = 36645336 (34.925048828125MB)  // 已使用空間
   free     = 242538024 (231.199951171875MB)  // 未使用空間
   13.11123171556415% used //空間使用率
...

-histo[:live]

該選項會輸出Java堆內存中的對象信息,包括對象的數量、佔用內存大小、類名等。如果加上”:live”參數,則只統計存活對象的信息。例如:

jmap -histo 19321

這條命令會輸出進程號19321對應的Java應用中對象的統計信息,例如:

num     #instances         #bytes  class name
----------------------------------------------
   1:        183765     474534880  [C  // char數組對象
   2:          8749     274628312  [B  // byte數組對象
   3:         21869     164735880  java.lang.String
   4:          9350      57402584  [I  // int數組對象
   5:        310942      49910872  java.util.LinkedHashMap$Entry
   ...

-dump:[live,]format=b,file=filename

該選項可以生成一個Java堆的dump文件,我們可以用jhat、MAT等工具來解析這個文件,進行一些內存分析。例如:

jmap -dump:live,format=b,file=heapdump.bin 19321

這條命令會生成進程號19321對應Java應用的存活對象的dump文件heapdump.bin。我們可以使用jhat工具來解析這個文件:

jhat heapdump.bin

然後在瀏覽器中訪問http://localhost:7000/即可查看內存分析報告。

三、jmap的優化實踐

1. 分析內存泄漏

使用jmap可以針對Java應用程序進行內存泄漏分析。如果應用程序出現了內存泄漏,就可以藉助jmap管理Java堆中的對象,通過GC日誌、堆轉儲文件等方式來確定內存泄漏的類型和原因。

下面是一個jmap分析內存泄漏的示例代碼:

public class MemoryLeak {

    private static List list = new LinkedList();

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 100000; i++) {
            list.add(new Object());
        }
        Thread.sleep(30000);
        list.clear();
        System.out.println("list size: " + list.size());
    }

}

在運行該程序之後,我們可以使用如下命令來獲取Java進程的pid:

jps -l

得到pid之後,我們可以使用如下命令來生成堆轉儲文件:

jmap -dump:live,format=b,file=heapdump.bin pid

使用MAT等工具,可以分析堆轉儲文件,找到內存泄漏的對象。例如,我們可以在MAT的Histogram視圖中查看對象數量排名前100的對象,如下圖所示:

可以看到,LinkedList$Entry對象數量排名第一,說明LinkedList中的節點佔用了大量的內存。打開該對象的histogram視圖,可以查看該對象的實例數量、大小、引用關係等信息,如下圖所示:

可以看到,可以直接從該對象的鏈表、size屬性追尋到具體的對象,從而找到內存泄漏的原因。

2. 分析OOM

jmap可以用於定位一個Java進程的OOM問題,步驟與上面類似。首先,需要在發生OOM的時候,使用jmap生成一個堆映射文件。這個文件可以與MAT等工具一起使用,從而進行內存分析。

下面是OOM的一些示例代碼:

public class OOMTest {

    private static List list = new LinkedList();

    public static void main(String[] args) throws InterruptedException {
        for (int i = 0; i < 10_000_000; i++) {
            list.add(new Object());
            if (i % 1000 == 0) {
                System.out.println("add object: " + i);
            }
        }
    }

}

在運行該程序之後,我們可以使用如下命令來獲取Java進程的pid:

jps -l

得到pid之後,我們可以使用如下命令來生成堆轉儲文件:

jmap -dump:live,format=b,file=heapdump.bin pid

使用MAT等工具,可以分析堆轉儲文件,找到OOM的原因。例如,我們可以在MAT的Histogram視圖中查看對象數量排名前10的對象,如下圖所示:

可以看到,Object實例的數量是最多的,Java應用在運行過程中創建了非常多的Object實例,使得堆內存被耗盡,從而發生了OOM。

四、jmap小結

jmap是一個非常強大的工具,可以幫助我們更好地了解Java應用程序的內存使用情況,從而進行優化。在實踐中,我們可以使用jmap分析內存泄漏、OOM等問題,從而根據分析結果對應用程序進行優化。

原創文章,作者:KTDSR,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/369467.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
KTDSR的頭像KTDSR
上一篇 2025-04-12 13:01
下一篇 2025-04-13 11:45

相關推薦

  • Python創建分配內存的方法

    在python中,我們常常需要創建並分配內存來存儲數據。不同的類型和數據結構可能需要不同的方法來分配內存。本文將從多個方面介紹Python創建分配內存的方法,包括列表、元組、字典、…

    編程 2025-04-29
  • lsw2u1:全能編程開發工程師的利器

    lsw2u1是一款多功能工具,可以為全能編程開發工程師提供便利的支持。本文將從多個方面對lsw2u1做詳細闡述,並給出對應代碼示例。 一、快速存取代碼段 在日常開發中,我們總會使用…

    編程 2025-04-29
  • Python刷課:優化學習體驗的利器

    Python刷課作為一種利用自動化技術優化學習體驗的工具已經被廣泛應用。它可以幫助用戶自動登錄、自動答題等,讓用戶在學習過程中可以更加專註於知識本身,提高效率,增加學習樂趣。 一、…

    編程 2025-04-29
  • Python命令大全及說明

    Python是一種高級編程語言,由Guido van Rossum於1989年底發明。它具有良好的語法結構和面向對象的編程思想,具有簡潔、易讀、易學的特點,是初學者以及專業開發人員…

    編程 2025-04-29
  • Python變量在內存中的存儲

    該文章將從多個方面對Python變量在內存中的存儲進行詳細闡述,包括變量的聲明和賦值、變量的引用和指向、內存地址的變化、內存管理機制等。 一、聲明和賦值 在Python中,變量聲明…

    編程 2025-04-29
  • Git config命令用法介紹:用正確的郵箱保障開發工作

    本文將詳細介紹如何使用git config命令配置Git的全局和本地用戶信息,特別是如何正確使用用戶郵箱,保障Git操作的正常進行。 一、git config命令介紹 Git中的每…

    編程 2025-04-29
  • Python SSH 遠程執行命令

    Python SSH 遠程執行命令是指在一個服務器上執行遠程另一個服務器上命令。如果你需要在本地機器上執行命令,或者在遠程機器上執行本地命令,你都可以使用 SSH。在 Python…

    編程 2025-04-29
  • Python計算內存佔用

    Python是一種高級的、解釋性的、面向對象的、動態的程序語言,因其易於學習、易於閱讀、可移植性好等優點,越來越受到開發者的青睞。當我們編寫Python代碼時,可能經常需要計算程序…

    編程 2025-04-28
  • 使用Go-Redis獲取Redis集群內存使用率

    本文旨在介紹如何使用Go-Redis獲取Redis集群的內存使用率。 一、Go-Redis簡介 Go-Redis是一個用於連接Redis服務器的Golang客戶端。它支持Redis…

    編程 2025-04-28
  • 剖析命令執行函數

    在編程開發過程中,命令執行函數是非常常見的一個概念。它是指接受一個命令字符串,並將其解析執行,返回相應的結果或錯誤信息的函數。本文將從多個方面對命令執行函數進行詳細的闡述,包括其定…

    編程 2025-04-28

發表回復

登錄後才能評論