5、jdk工具之jmap(java memory map)、 mat之四--結合mat對內存泄露的分析、jhat之二--結合jmap生成的dump結果在瀏覽器上展現

目錄

1、jdk工具之jps(JVM Process Status Tools)命令使用html

2、jdk命令之javah命令(C Header and Stub File Generator)java

3、jdk工具之jstack(Java Stack Trace)算法

4、jdk工具之jstat命令(Java Virtual Machine Statistics Monitoring Tool)緩存

4、jdk工具之jstat命令2(Java Virtual Machine Statistics Monitoring Tool)詳解app

5、jdk工具之jmap(java memory map)、 mat之四--結合mat對內存泄露的分析eclipse

6、jdk工具之jinfo命令(Java Configuration Info)jvm

7、jdk工具之jconsole命令(Java Monitoring and Management Console)工具

8、jdk工具之JvisualVM、JvisualVM之二--Java程序性能分析工具Java VisualVMpost

9、jdk工具之jhat命令(Java Heap Analyse Tool)性能

10、jdk工具之Jdb命令(The Java Debugger)

11、jdk命令之Jstatd命令(Java Statistics Monitoring Daemon)

11、jdk命令之Jstatd命令(Java Statistics Monitoring Daemon)

12、jdk工具之jcmd介紹(堆轉儲、堆分析、獲取系統信息、查看堆外內存)

十3、jdk命令之Java內存之本地內存分析神器:NMT 和 pmap

 

 

一、介紹

打印出某個java進程(使用pid)內存內的,全部‘對象’的狀況(如:產生那些對象,及其數量)。

能夠輸出全部內存中對象的工具,甚至能夠將VM 中的heap,以二進制輸出成文本。使用方法 jmap -histo pid。若是連用SHELL jmap -histo pid>a.log能夠將其保存到文本中去,在一段時間後,使用文本對比工具,能夠對比出GC回收了哪些對象。jmap -dump:format=b,file=outfile 3024能夠將3024進程的內存heap輸出出來到outfile文件裏,再配合MAT(內存分析工具(Memory Analysis Tool),使用參見:http://blog.csdn.net/fenglibing/archive/2011/04/02/6298326.aspx)或與jhat (Java Heap Analysis Tool)一塊兒使用,可以以圖像的形式直觀的展現當前內存是否有問題。

查看該進程(pid)下堆內存的使用狀況:

jmap -heap pid

快速定位內存泄漏的方法:只統計存活的對象

jmap -histo:live pid

還能夠導出:

jmap -histo:live pid >1.txt將信息輸出到指定文件中

 

二、命令格式

SYNOPSIS

       jmap [ option ] pid

       jmap [ option ] executable core

       jmap [ option ] [server-id@]remote-hostname-or-IP

三、參數說明

1)、options: 

executable Java executable from which the core dump was produced.

(多是產生core dump的java可執行程序)

core 將被打印信息的core dump文件

remote-hostname-or-IP 遠程debug服務的主機名或ip

server-id 惟一id,假如一臺主機上多個遠程debug服務 

2)、基本參數:

-dump:[live,]format=b,file=<filename> 使用hprof二進制形式,輸出jvm的heap內容到文件=. live子選項是可選的,假如指定live選項,那麼只輸出活的對象到文件. 

-finalizerinfo 打印正等候回收的對象的信息.

-heap 打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用狀況.

-histo[:live] 打印每一個class的實例數目,內存佔用,類全名信息. VM的內部類名字開頭會加上前綴」*」. 若是live子參數加上後,只統計活的對象數量. 

-permstat 打印classload和jvm heap長久層的信息. 包含每一個classloader的名字,活潑性,地址,父classloader和加載的class數量. 另外,內部String的數量和佔用內存數也會打印出來. 

-F 強迫.在pid沒有相應的時候使用-dump或者-histo參數. 在這個模式下,live子參數無效. 

-h | -help 打印輔助信息 

-J 傳遞參數給jmap啓動的jvm. 

pid 須要被打印配相信息的java進程id,創業與打工的區別 - 博文預覽,能夠用jps查問.

四、使用示例

tasklist命令查看進程id(Tasklist"是 winxp/win2003/vista/win7/win8下的命令,用來顯示運行在本地或遠程計算機上的全部進程,帶有多個執行參數。)

 

經常使用的參數以下:

histo

jmap -histo pid 展現class的內存狀況

展現的信息爲編號,實例數,字節,類名

-finalizerinfo   

打印等待回收的對象信息

jmap -finalizerinfo 4783
Attaching to process ID 4783, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.171-b11
Number of objects pending for finalization: 0
[root@ip-172-29-206-104 applogs]#

 

heap

jmap -heap pid 展現pid的總體堆信息

複製代碼
    jmap -heap 2464  
    JVM version is 16.3-b01  
      
    using thread-local object allocation.  
    Parallel GC with 13 thread(s)  
      
    Heap Configuration:  
       MinHeapFreeRatio = 40  
       MaxHeapFreeRatio = 70  
       MaxHeapSize      = 8436842496 (8046.0MB)  
       NewSize          = 5439488 (5.1875MB)  
       MaxNewSize       = 17592186044415 MB  
       OldSize          = 5439488 (5.1875MB)  
       NewRatio         = 2  
       SurvivorRatio    = 8  
       PermSize         = 21757952 (20.75MB)  
       MaxPermSize      = 88080384 (84.0MB)  
      
    Heap Usage:  
    PS Young Generation  
    Eden Space:  
       capacity = 87883776 (83.8125MB)  
       used     = 31053080 (29.614524841308594MB)  
       free     = 56830696 (54.197975158691406MB)  
       35.33425782706469% used  
    From Space:  
       capacity = 13828096 (13.1875MB)  
       used     = 196608 (0.1875MB)  
       free     = 13631488 (13.0MB)  
       1.4218009478672986% used  
    To Space:  
       capacity = 16384000 (15.625MB)  
       used     = 0 (0.0MB)  
       free     = 16384000 (15.625MB)  
       0.0% used  
    PS Old Generation  
       capacity = 156172288 (148.9375MB)  
       used     = 27098208 (25.842864990234375MB)  
       free     = 129074080 (123.09463500976562MB)  
       17.35148299805917% used  
    PS Perm Generation  
       capacity = 88080384 (84.0MB)  
       used     = 50847592 (48.492042541503906MB)  
       free     = 37232792 (35.507957458496094MB)  
       57.728622073218936% used  
複製代碼

說明以下

Parallel GC with 13 thread(s)   #13個gc線程  
  
Heap Configuration:#堆內存初始化配置  
   MinHeapFreeRatio = 40  #-XX:MinHeapFreeRatio設置JVM堆最小空閒比率  
   MaxHeapFreeRatio = 70  #-XX:MaxHeapFreeRatio設置JVM堆最大空閒比率  
   MaxHeapSize      = 8436842496 (8046.0MB)#-XX:MaxHeapSize=設置JVM堆的最大大小  
   NewSize          = 5439488 (5.1875MB) #-XX:NewSize=設置JVM堆的‘新生代’的默認大小  
   MaxNewSize       = 17592186044415 MB  #-XX:MaxNewSize=設置JVM堆的‘新生代’的最大大小  
   OldSize          = 5439488 (5.1875MB) #-XX:OldSize=設置JVM堆的‘老生代’的大小  
   NewRatio         = 2 #-XX:NewRatio=:‘新生代’和‘老生代’的大小比率  
   SurvivorRatio    = 8 #-XX:SurvivorRatio=設置年輕代中Eden區與Survivor區的大小比值  
   PermSize         = 21757952 (20.75MB) #-XX:PermSize=<value>:設置JVM堆的‘永生代’的初始大小  
   MaxPermSize      = 88080384 (84.0MB) #-XX:MaxPermSize=<value>:設置JVM堆的‘永生代’的最大大小  
  
Heap Usage:  
PS Young Generation  
Eden Space:#Eden區內存分佈  
   capacity = 87883776 (83.8125MB)  
   used     = 31053080 (29.614524841308594MB)  
   free     = 56830696 (54.197975158691406MB)  
   35.33425782706469% used  
From Space:#其中一個Survivor區的內存分佈  
   capacity = 13828096 (13.1875MB)  
   used     = 196608 (0.1875MB)  
   free     = 13631488 (13.0MB)  
   1.4218009478672986% used  
To Space:#另外一個Survivor區的內存分佈  
   capacity = 16384000 (15.625MB)  
   used     = 0 (0.0MB)  
   free     = 16384000 (15.625MB)  
   0.0% used  
PS Old Generation#當前的Old區內存分佈  
   capacity = 156172288 (148.9375MB)  
   used     = 27098208 (25.842864990234375MB)  
   free     = 129074080 (123.09463500976562MB)  
   17.35148299805917% used  
PS Perm Generation#當前的 「永生代」 內存分佈  
   capacity = 88080384 (84.0MB)  
   used     = 50847592 (48.492042541503906MB)  
   free     = 37232792 (35.507957458496094MB)  
   57.728622073218936% used

mat爲eclipse的一個內存分析插件,幫助查找內存泄漏和減小內存消耗。

首先基於jmap導出的堆信息

jmap -dump:live,format=b,file=test.bin 29030  

 準備代碼:

class User {  
    private String id;  
    private String name;  
  
    public String getId() {  
        return id;  
    }  
  
    public void setId(String id) {  
        this.id = id;  
    }  
  
    public String getName() {  
        return name;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    public User(String id, String name) {  
        super();  
        this.id = id;  
        this.name = name;  
    }  
  
}  

 main方法:

public static void main(String[] args) {  
    List<User> list = new ArrayList<User>();  
    for (int i = 1; i < 10000; i++) {  
        User o = new User(i + "", System.currentTimeMillis() + "");  
        list.add(o);  
        o = null;  
    }  
    System.out.println("end");  
    try {  
        Thread.sleep(100000000l);  
    } catch (InterruptedException e) {  
        e.printStackTrace();  
    }  
}  

 執行以後用jmap輸出堆信息

而後導入分析工具

咱們能夠看到圖形化展現:



 而後咱們點擊

Problem Suspect 1

以下所示:



 而後點擊詳情



 咱們能夠看到有不少的User對象



 這些對象有可能會溢出,而後咱們打開OQL窗口看他是否爲null,執行以下OQL語句

SELECT u FROM org.learn.util.User u WHERE (u.value = null)  

 

 結果以下:


 也就是說這個是null,可是仍然有強引用存在,gc的時候是不能回收的,這樣就會出現內存的溢出問題

 示例2:如何用mat分析內存問題

我用MAT打開了heap.bin,很容易看出,char[]的數量出其意料的多,佔用90%以上的內存 。通常來講,char[]在JVM確實會佔用不少內存,數量也很是多,由於String對象以char[]做爲內部存儲。可是此次的char[]太貪婪 了,仔細一觀察,發現有數萬計的char[],每一個都佔用數百K的內存 。這個現象說明,Java程序保存了數以萬計的大String對象 。結合程序的邏輯,這個是不該該的,確定在某個地方出了問題。

在可疑的char[]中,任意挑了一個,使用Path To GC Root功能,找到該char[]的引用路徑,發現String對象是被一個HashMap中引用的 。這個也是意料中的事情,Java的內存泄露多半是由於對象被遺留在全局的HashMap中得不到釋放。不過,該HashMap被用做一個緩存,設置了緩 存條目的閾值,導達到閾值後會自動淘汰。從這個邏輯分析,應該不會出現內存泄露的。雖然緩存中的String對象已經達到數萬計,但仍然沒有達到預先設置 的閾值(閾值設置地比較大,由於當時預估String對象都比較小)。

 

    可是,另外一個問題引發了個人注意:爲何緩存的String對象如此巨大?內部char[]的長度達數百K。雖然緩存中的 String對象數量尚未達到閾值,可是String對象大小遠遠超出了咱們的預期,最終致使內存被大量消耗,造成內存泄露的跡象(準確說應該是內存消 耗過多) 。

 

    就這個問題進一步順藤摸瓜,看看String大對象是如何被放到HashMap中的。經過查看程序的源代碼,我發現,確實有String大對象,不 過並無把String大對象放到HashMap中,而是把String大對象進行split(調用String.split方法),而後將split出 來的String小對象放到HashMap中 了。

 

    這就奇怪了,放到HashMap中明明是split以後的String小對象,怎麼會佔用那麼大空間呢?難道是String類的split方法有問題?

相關文章
相關標籤/搜索