java命令--jmap命令使用(查找内存泄漏对象)
轉(zhuǎn)自:https://www.cnblogs.com/kongzhongqijing/articles/3621163.html
jdk安裝后會(huì)自帶一些小工具,jmap命令(Java Memory Map)是其中之一。主要用于打印指定Java進(jìn)程(或核心文件、遠(yuǎn)程調(diào)試服務(wù)器)的共享對(duì)象內(nèi)存映射或堆內(nèi)存細(xì)節(jié)。
jmap命令可以獲得運(yùn)行中的jvm的堆的快照,從而可以離線分析堆,以檢查內(nèi)存泄漏,檢查一些嚴(yán)重影響性能的大對(duì)象的創(chuàng)建,檢查系統(tǒng)中什么對(duì)象最多,各種對(duì)象所占內(nèi)存的大小等等??梢允褂胘map生成Heap Dump。
java memory = direct memory(直接內(nèi)存) + jvm memory(MaxPermSize +Xmx)
1)直接內(nèi)存跟堆
直接內(nèi)存則是一塊由程序本身管理的一塊內(nèi)存空間,它的效率要比標(biāo)準(zhǔn)內(nèi)存池要高,主要用于存放網(wǎng)絡(luò)通信時(shí)數(shù)據(jù)緩沖和磁盤數(shù)據(jù)交換時(shí)的數(shù)據(jù)緩沖。
DirectMemory容量可以通過 -XX:MaxDirectMemorySize指定,如果不指定,則默認(rèn)為與Java堆的最大值(-Xmx指定)一樣。但是,在OSX上的最新版本的 JVM,對(duì)直接內(nèi)存的默認(rèn)大小進(jìn)行修訂,改為“在不指定直接內(nèi)存大小的時(shí)默認(rèn)分配的直接內(nèi)存大小為64MB”,可以通過 -XX:MaxMemorySize來顯示指定直接內(nèi)存的大小。
2)堆(Heap)和非堆(Non-heap)內(nèi)存
按照官方的說法:“Java 虛擬機(jī)具有一個(gè)堆,堆是運(yùn)行時(shí)數(shù)據(jù)區(qū)域,所有類實(shí)例和數(shù)組的內(nèi)存均從此處分配。堆是在 Java 虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建的。”“在JVM中堆之外的內(nèi)存稱為非堆內(nèi)存(Non-heap memory)”。
可以看出JVM主要管理兩種類型的內(nèi)存:堆和非堆。簡單來說堆就是Java代碼可及的內(nèi)存,是留給開發(fā)人員使用的;非堆就是JVM留給自己用的,
所以方法區(qū)、JVM內(nèi)部處理或優(yōu)化所需的內(nèi)存(如JIT編譯后的代碼緩存)、每個(gè)類結(jié)構(gòu)(如運(yùn)行時(shí)常數(shù)池、字段和方法數(shù)據(jù))以及方法和構(gòu)造方法的代碼都在非堆內(nèi)存中。
3)棧與堆
棧解決程序的運(yùn)行問題,即程序如何執(zhí)行,或者說如何處理數(shù)據(jù);堆解決的是數(shù)據(jù)存儲(chǔ)的問題,即數(shù)據(jù)怎么放、放在哪兒。
在Java中一個(gè)線程就會(huì)相應(yīng)有一個(gè)線程棧與之對(duì)應(yīng),這點(diǎn)很容易理解,因?yàn)椴煌木€程執(zhí)行邏輯有所不同,因此需要一個(gè)獨(dú)立的線程棧。而堆則是所有線程共享的。棧因?yàn)槭沁\(yùn)行單位,因此里面存儲(chǔ)的信息都是跟當(dāng)前線程(或程序)相關(guān)信息的。包括局部變量、程序運(yùn)行狀態(tài)、方法返回值等等;而堆只負(fù)責(zé)存儲(chǔ)對(duì)象信息。
Java的堆是一個(gè)運(yùn)行時(shí)數(shù)據(jù)區(qū),類的(對(duì)象從中分配空間。這些對(duì)象通過new、newarray、anewarray和multianewarray等 指令建立,它們不需要程序代碼來顯式的釋放。堆是由垃圾回收來負(fù)責(zé)的,堆的優(yōu)勢(shì)是可以動(dòng)態(tài)地分配內(nèi)存大小,生存期也不必事先告訴編譯器,因?yàn)樗窃谶\(yùn)行時(shí) 動(dòng)態(tài)分配內(nèi)存的,Java的垃圾收集器會(huì)自動(dòng)收走這些不再使用的數(shù)據(jù)。但缺點(diǎn)是,由于要在運(yùn)行時(shí)動(dòng)態(tài)分配內(nèi)存,存取速度較慢。 棧的優(yōu)勢(shì)是,存取速度比堆要快,僅次于寄存器,棧數(shù)據(jù)可以共享。但缺點(diǎn)是,存在棧中的數(shù)據(jù)大小與生存期必須是確定的,缺乏靈活性。棧中主要存放一些基本類 型的變量(,int, short, long, byte, float, double, boolean, char)和對(duì)象句柄。
線程占用大小在MaxPermSize中進(jìn)行內(nèi)存申請(qǐng)和分配
什么是堆Dump
堆Dump是反應(yīng)Java堆使用情況的內(nèi)存鏡像,其中主要包括系統(tǒng)信息、虛擬機(jī)屬性、完整的線程Dump、所有類和對(duì)象的狀態(tài)等。 一般,在內(nèi)存不足、GC異常等情況下,我們就會(huì)懷疑有內(nèi)存泄露。這個(gè)時(shí)候我們就可以制作堆Dump來查看具體情況。分析原因。
基礎(chǔ)知識(shí)
Java虛擬機(jī)的內(nèi)存組成以及堆內(nèi)存介紹Java GC工作原理常見內(nèi)存錯(cuò)誤:
outOfMemoryError年老代內(nèi)存不足。
outOfMemoryError:PermGen Space永久代內(nèi)存不足。
outOfMemoryError:GC overhead limit exceed垃圾回收時(shí)間占用系統(tǒng)運(yùn)行時(shí)間的98%或以上。
一、介紹
打印出某個(gè)java進(jìn)程(使用pid)內(nèi)存內(nèi)的,所有‘對(duì)象’的情況(如:產(chǎn)生那些對(duì)象,及其數(shù)量)。它的用途是為了展示java進(jìn)程的內(nèi)存映射信息,或者堆內(nèi)存詳情。
可以輸出所有內(nèi)存中對(duì)象的工具,甚至可以將VM中的heap,以二進(jìn)制輸出成文本。
jmap -heap:format=b pid bin格式 javaversion 1.5
jmap -dump:format=b,file=filename pid javaversion >1.6
jmap-dump:format=b,file=outfile3024可以將3024進(jìn)程的內(nèi)存heap輸出出來到outfile文件里,再配合MAT(內(nèi)存分析工具(MemoryAnalysisTool)或與jhat(JavaHeapAnalysisTool)一起使用,能夠以圖像的形式直觀的展示當(dāng)前內(nèi)存是否有問題。
64位機(jī)上使用需要使用如下方式:
jmap-J-d64-heappid
二、命令格式
SYNOPSIS
jmap [ option ] pid(toconnecttoremotedebugserver)
jmap [ option ] executable core(toconnecttoremotedebugserver)
jmap [ option ] [server-id@]remote-hostname-or-IP(toconnecttoremotedebugserver)
where <option> is one of: <none> to print same info as Solaris pmap -heap to print java heap summary -histo[:live] to print histogram of java object heap; if the "live" suboption is specified, only count live objects
-permstat to print permanent generation statistics -finalizerinfo to print information on objects awaiting finalization -dump:<dump-options> to dump java heap in hprof binary format dump-options: live dump only live objects; if not specified,all objects in the heap are dumped.
format=b binary format file=<file> dump heap to <file> Example: jmap -dump:live,format=b,file=heap.bin <pid>
-F force. Use with -dump:<dump-options> <pid> or -histo to force a heap dump or histogram when <pid> does not respond. The "live" suboption is not supported in this mode. -h | -help to print this help message -J<flag> to pass <flag> directly to the runtime system
參數(shù)如下: -heap:打印jvm heap的情況 -histo:打印jvm heap的直方圖。其輸出信息包括類名,對(duì)象數(shù)量,對(duì)象占用大小。
-histo:live :同上,但是只答應(yīng)存活對(duì)象的情況
-permstat:打印permanent generation heap情況
參數(shù)說明:
1)、options:
executable Java executable from which the core dump was produced.(可能是產(chǎn)生core dump的java可執(zhí)行程序)
core將被打印信息的core dump文件
remote-hostname-or-IP 遠(yuǎn)程debug服務(wù)的主機(jī)名或ip
server-id 唯一id,假如一臺(tái)主機(jī)上多個(gè)遠(yuǎn)程debug服務(wù),用此選項(xiàng)參數(shù)標(biāo)識(shí)服務(wù)器
2)基本參數(shù):
<no option>如果使用不帶選項(xiàng)參數(shù)的jmap打印共享對(duì)象映射,將會(huì)打印目標(biāo)虛擬機(jī)中加載的每個(gè)共享對(duì)象的起始地址、映射大小以及共享對(duì)象文件的路徑全稱。這與Solaris的pmap工具比較相似。
-dump:[live,]format=b,file=<filename>使用hprof二進(jìn)制形式,輸出jvm的heap內(nèi)容到文件, live子選項(xiàng)是可選的,假如指定live選項(xiàng),那么只輸出活的對(duì)象到文件.
-finalizerinfo 打印正等候回收的對(duì)象的信息.
-heap打印heap的概要信息,GC使用的算法,heap的配置及wise heap的使用情況.
-histo[:live]打印每個(gè)class的實(shí)例數(shù)目,內(nèi)存占用,類全名信息. VM的內(nèi)部類名字開頭會(huì)加上前綴”*”. 如果live子參數(shù)加上后,只統(tǒng)計(jì)活的對(duì)象數(shù)量.
-permstat 打印classload和jvm heap長久層的信息. 包含每個(gè)classloader的名字,活潑性,地址,父classloader和加載的class數(shù)量. 另外,內(nèi)部String的數(shù)量和占用內(nèi)存數(shù)也會(huì)打印出來.
-F 強(qiáng)迫.在pid沒有響應(yīng)的時(shí)候使用-dump或者-histo參數(shù). 在這個(gè)模式下,live子參數(shù)無效.
-h | -help 打印輔助信息
-J<flag> 傳遞參數(shù)給jmap啟動(dòng)的jvm.
pid 需要被打印配相信息的java進(jìn)程id,可以用jps查問
從安全點(diǎn)日志看,從Heap Dump開始,整個(gè)JVM都是停頓的,考慮到IO(雖是寫到Page Cache,但或許會(huì)遇到background flush),幾G的Heap可能產(chǎn)生幾秒的停頓,在生產(chǎn)環(huán)境上執(zhí)行時(shí)謹(jǐn)慎再謹(jǐn)慎。
live的選項(xiàng),實(shí)際上是產(chǎn)生一次Full GC來保證只看還存活的對(duì)象。有時(shí)候也會(huì)故意不加live選項(xiàng),看歷史對(duì)象。
Dump出來的文件建議用JDK自帶的VisualVM或Eclipse的MAT插件打開,對(duì)象的大小有兩種統(tǒng)計(jì)方式:
本身大小(Shallow Size):對(duì)象本來的大小。
保留大小(Retained Size): 當(dāng)前對(duì)象大小 + 當(dāng)前對(duì)象直接或間接引用到的對(duì)象的大小總和。
看本身大小時(shí),占大頭的都是char[] ,byte[]之類的,沒什么意思(用jmap -histo:live pid 看的也是本身大小)。所以需要關(guān)心的是保留大小比較大的對(duì)象,看誰在引用這些char[], byte[]。
(MAT能看的信息更多,但VisualVM勝在JVM自帶,用法如下:命令行輸入jvisualvm,文件->裝入->堆Dump->檢查 -> 查找20保留大小最大的對(duì)象,就會(huì)觸發(fā)保留大小的計(jì)算,然后就可以類視圖里瀏覽,按保留大小排序了)
三、使用實(shí)例
1、jmap -heap pid 展示pid的整體堆信息
#ps -ef|grep tomcat #獲取tomcat的pid
[root@localhost ~]# jmap -heap 27900 Attaching to process ID 27900, please wait... Debugger attached successfully. Client compiler detected. JVM version is 20.45-b01 using thread-local object allocation. Mark Sweep Compact GC Heap Configuration: #堆內(nèi)存初始化配置 MinHeapFreeRatio = 40 #-XX:MinHeapFreeRatio設(shè)置JVM堆最小空閑比率 MaxHeapFreeRatio = 70 #-XX:MaxHeapFreeRatio設(shè)置JVM堆最大空閑比率 MaxHeapSize = 100663296 (96.0MB) #-XX:MaxHeapSize=設(shè)置JVM堆的最大大小 NewSize = 1048576 (1.0MB) #-XX:NewSize=設(shè)置JVM堆的‘新生代’的默認(rèn)大小 MaxNewSize = 4294901760 (4095.9375MB) #-XX:MaxNewSize=設(shè)置JVM堆的‘新生代’的最大大小 OldSize = 4194304 (4.0MB) #-XX:OldSize=設(shè)置JVM堆的‘老生代’的大小 NewRatio = 2 #-XX:NewRatio=:‘新生代’和‘老生代’的大小比率 SurvivorRatio = 8 #-XX:SurvivorRatio=設(shè)置年輕代中Eden區(qū)與Survivor區(qū)的大小比值 PermSize = 12582912 (12.0MB) #-XX:PermSize=<value>:設(shè)置JVM堆的‘持久代’的初始大小 MaxPermSize = 67108864 (64.0MB) #-XX:MaxPermSize=<value>:設(shè)置JVM堆的‘持久代’的最大大小 Heap Usage: New Generation (Eden + 1 Survivor Space): #新生代區(qū)內(nèi)存分布,包含伊甸園區(qū)+1個(gè)Survivor區(qū) capacity = 30212096 (28.8125MB) used = 27103784 (25.848182678222656MB) free = 3108312 (2.9643173217773438MB) 89.71169693092462% used Eden Space: #Eden區(qū)內(nèi)存分布 capacity = 26869760 (25.625MB) used = 26869760 (25.625MB) free = 0 (0.0MB) 100.0% used From Space: #其中一個(gè)Survivor區(qū)的內(nèi)存分布 capacity = 3342336 (3.1875MB) used = 234024 (0.22318267822265625MB) free = 3108312 (2.9643173217773438MB) 7.001809512867647% used To Space: #另一個(gè)Survivor區(qū)的內(nèi)存分布 capacity = 3342336 (3.1875MB) used = 0 (0.0MB) free = 3342336 (3.1875MB) 0.0% used tenured generation: #當(dāng)前的Old區(qū)內(nèi)存分布 capacity = 67108864 (64.0MB) used = 67108816 (63.99995422363281MB) free = 48 (4.57763671875E-5MB) 99.99992847442627% used Perm Generation: #當(dāng)前的 “持久代” 內(nèi)存分布 capacity = 14417920 (13.75MB) used = 14339216 (13.674942016601562MB) free = 78704 (0.0750579833984375MB) 99.45412375710227% used
新生代的內(nèi)存回收就是采用空間換時(shí)間的方式;
如果from區(qū)使用率一直是100% 說明程序創(chuàng)建大量的短生命周期的實(shí)例,使用jstat統(tǒng)計(jì)一下jvm在內(nèi)存回收中發(fā)生的頻率耗時(shí)以及是否有full gc,使用這個(gè)數(shù)據(jù)來評(píng)估一內(nèi)存配置參數(shù)、gc參數(shù)是否合理;
多次ygc后如果s區(qū)沒變化,這種情況不出意外就是擔(dān)保了,可以jstat持續(xù)觀察下;
[root@localhost ~]# jmap -heap 4951 Attaching to process ID 4951, please wait... Debugger attached successfully. Client compiler detected. JVM version is 20.45-b01 using thread-local object allocation. Parallel GC with 1 thread(s) Heap Configuration: MinHeapFreeRatio = 40 MaxHeapFreeRatio = 70 MaxHeapSize = 734003200 (700.0MB) NewSize = 314572800 (300.0MB) MaxNewSize = 314572800 (300.0MB) OldSize = 4194304 (4.0MB) NewRatio = 2 SurvivorRatio = 8 PermSize = 104857600 (100.0MB) MaxPermSize = 104857600 (100.0MB) Heap Usage: PS Young Generation Eden Space: capacity = 235929600 (225.0MB) used = 169898184 (162.02753448486328MB) free = 66031416 (62.97246551513672MB) 72.01223754882812% used From Space: capacity = 39321600 (37.5MB) used = 0 (0.0MB) free = 39321600 (37.5MB) 0.0% used To Space: capacity = 39321600 (37.5MB) used = 0 (0.0MB) free = 39321600 (37.5MB) 0.0% used PS Old Generation capacity = 419430400 (400.0MB) used = 0 (0.0MB) free = 419430400 (400.0MB) 0.0% used PS Perm Generation capacity = 104857600 (100.0MB) used = 14140688 (13.485610961914062MB) free = 90716912 (86.51438903808594MB) 13.485610961914062% used
根據(jù)打印的結(jié)果:默認(rèn)存活區(qū)與eden比率=2:8
1)查看eden區(qū):225M
2)兩個(gè)存活區(qū)大小:都為37.5M
3)年輕代大?。?00M
4)老年代大?。?00M
5)持久代大?。?00M
6)最大堆內(nèi)存大小:年輕代大小+老年代大小=700M
7)java應(yīng)用程序占用內(nèi)存大?。鹤畲蠖褍?nèi)存大小+持久代大小=700M+100M=800M
對(duì)應(yīng)java參數(shù)(在tomcat的啟動(dòng)文件里)配置如下:
JAVA_OPTS="-Xms700m -Xmx700m -Xmn300m -Xss1024K -XX:PermSize=100m -XX:MaxPermSize=100 -XX:+UseParallelGC -XX:ParallelGCThreads=1 -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:/opt/logs/gc.log -verbose:gc -XX:+DisableExplicitGC"
注意參數(shù)配置時(shí),上述參數(shù)為一行。
各參數(shù)意義:
Xms
Xmx
Xmn
Xss
-XX:PermSize
-XX:MaxPermSize
NewRatio = 2 表示新生代(e+2s):老年代(不含永久區(qū))=1:2,指新生代占整個(gè)堆的1/3
SurvivorRatio = 8 表示2個(gè)S:eden=2:8,一個(gè)S占年輕代的1/10
2、jmap -histo pid 展示class的內(nèi)存情況
說明:instances(實(shí)例數(shù))、bytes(大?。lasss name(類名)。它基本是按照使用使用大小逆序排列的。
#instance 是對(duì)象的實(shí)例個(gè)數(shù) #bytes 是總占用的字節(jié)數(shù) class name 對(duì)應(yīng)的就是 Class 文件里的 class 的標(biāo)識(shí) B 代表 byte C 代表 char D 代表 double F 代表 float I 代表 int J 代表 long Z 代表 boolean 前邊有 [ 代表數(shù)組, [I 就相當(dāng)于 int[] 對(duì)象用 [L+ 類名表示
從打印結(jié)果可看出,類名中存在[C、[B等內(nèi)容,
只知道它占用了那么大的內(nèi)存,但不知道由什么對(duì)象創(chuàng)建的。下一步需要將其他dump出來,使用內(nèi)存分析工具進(jìn)一步明確它是由誰引用的、由什么對(duì)象。
3、jmap-histo:live pid>a.log
可以觀察heap中所有對(duì)象的情況(heap中所有生存的對(duì)象的情況)。包括對(duì)象數(shù)量和所占空間大小??梢詫⑵浔4娴轿谋局腥?,在一段時(shí)間后,使用文本對(duì)比工具,可以對(duì)比出GC回收了哪些對(duì)象。
jmap -histo:live 這個(gè)命令執(zhí)行,JVM會(huì)先觸發(fā)gc,然后再統(tǒng)計(jì)信息。
4、dump將內(nèi)存使用的詳細(xì)情況輸出到文件
jmap -dump:live,format=b,file=a.log pid
說明:內(nèi)存信息dump到a.log文件中。
這個(gè)命令執(zhí)行,JVM會(huì)將整個(gè)heap的信息dump寫入到一個(gè)文件,heap如果比較大的話,就會(huì)導(dǎo)致這個(gè)過程比較耗時(shí),并且執(zhí)行的過程中為了保證dump的信息是可靠的,所以會(huì)暫停應(yīng)用。
該命令通常用來分析內(nèi)存泄漏OOM,通常做法是:
1)首先配置JVM啟動(dòng)參數(shù),讓JVM在遇到OutOfMemoryError時(shí)自動(dòng)生成Dump文件
-XX:+HeapDumpOnOutOfMemoryError-XX:HeapDumpPath=/path
2)然后使用命令
jmap-dump:format=b,file=/path/heap.bin進(jìn)程ID
如果只dump heap中的存活對(duì)象,則加上選項(xiàng)-live。
3)然后使用MAT分析工具,如jhat命令,eclipse的mat插件。
最后在eclipse中安裝MAT插件(http://www.eclipse.org/mat/),然后在eclipse中,file---->open,打開這個(gè)文件heap.bin,利用現(xiàn)成的OOM工具進(jìn)行分析。
具體操作方法:
首先輸入網(wǎng)址http://www.eclipse.org/mat/previousReleases.php,然后查看你自己的Eclipse版本,我的是Indigo的,所以點(diǎn)擊鏈接“PreviousReleases”,選擇Indigo版本的URLhttp://download.eclipse.org/mat/1.1.0/update-site/
用jhat命令可以參看jhat -port 5000 heapDump在瀏覽器中訪問:http://localhost:5000/查看詳細(xì)信息
四、性能問題查找
轉(zhuǎn)自:http://www.cnblogs.com/gaojk/articles/3886503.html
1、發(fā)現(xiàn)問題
1)、使用uptime命令查看CPU的Load情況,Load越高說明問題越嚴(yán)重;
2)、使用jstat查看FGC發(fā)生的頻率及FGC所花費(fèi)的時(shí)間,F(xiàn)GC發(fā)生的頻率越快、花費(fèi)的時(shí)間越高,問題越嚴(yán)重;
2、導(dǎo)出數(shù)據(jù):在應(yīng)用快要發(fā)生FGC的時(shí)候把堆導(dǎo)出來
1)、查看快要發(fā)生FGC使用命令:
jmap -heap <pid>
會(huì)看到如下圖結(jié)果:
以上截圖包括了新生代、老年代及持久代的當(dāng)前使用情況,如果不停的重復(fù)上面的命令,會(huì)看到這些數(shù)字的變化,變化越大說明系統(tǒng)存在問題的可能性越大,特別是被紅色圈起來的老年代的變化情況?,F(xiàn)在看到的這個(gè)值為使用率為99%或才快接近的時(shí)候,就立即可以執(zhí)行導(dǎo)出堆棧的操作了。
注:這是因?yàn)槲疫@里沒有在jvm參數(shù)中使用"-server"參數(shù),也沒有指定FGC的閥值,在線上的應(yīng)用中通過會(huì)指定CMSInitiatingOccupancyFraction這個(gè)參數(shù)來指定當(dāng)老年代使用了百分之多少的時(shí)候,通過CMS進(jìn)行FGC,當(dāng)然這個(gè)參數(shù)需要和這些參數(shù)一起使用“-XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:+UseCMSInitiatingOccupancyOnly”,CMSInitiatingOccupancyFraction的默認(rèn)值是68,現(xiàn)在中文站線上的應(yīng)用都是70,也就是說當(dāng)老年代使用率真達(dá)到或者超過70%時(shí),就會(huì)進(jìn)行FGC。
2)、將數(shù)據(jù)導(dǎo)出:
jmap -dump:format=b,file=heap.bin <pid>
這個(gè)時(shí)候會(huì)在當(dāng)前目錄以生成一個(gè)heap.bin這個(gè)二進(jìn)制文件。
3、通過命令查看大對(duì)象
也是使用jmap的命令,只不過參數(shù)使用-histo
使用:jmap -histo <pid>|less
可得到如下包含對(duì)象序號(hào)、某個(gè)對(duì)象示例數(shù)、當(dāng)前對(duì)象所占內(nèi)存的大小、當(dāng)前對(duì)象的全限定名,如下圖:
查看對(duì)象數(shù)最多的對(duì)象,并按降序排序輸出:
執(zhí)行:jmap -histo <pid>|grep alibaba|sort -k 2 -g -r|less
結(jié)果如圖:
查看占用內(nèi)存最多的最象,并按降序排序輸出:
執(zhí)行:jmap -histo <pid>|grep alibaba|sort -k 3 -g -r|less
結(jié)果如圖:
4、數(shù)據(jù)分析
這個(gè)時(shí)候?qū)ump出的文件在ECLIPSE中打開,使用MAT進(jìn)行分析(ECLIPSE需要先安裝MAT插件),會(huì)展示如下截圖:
可以從這個(gè)圖看出這個(gè)類java.lang.ref.Finalizer占用500多M,表示這其中很多不能夠被回對(duì)象的對(duì)象,此時(shí)點(diǎn)開hisgogram視圖,并通過Retained Heap進(jìn)行排序,如下截圖:
從圖中可以看出,被線線框圈起來的三個(gè)對(duì)象占用量非常大,那說明這幾個(gè)大的對(duì)象并沒有被釋放,那現(xiàn)在就可以有針對(duì)性的從代碼中去找這幾個(gè)對(duì)象為什么沒有被釋放了。
再切換到dominator_tree視圖:
這里可以看到velocity渲染也存在著問題,以及數(shù)據(jù)庫的請(qǐng)求也比較多。
5、優(yōu)化
優(yōu)化的思路就是上面所列出來的問題,查看實(shí)現(xiàn)代碼中所存在問題,具體問題具體分析。
總結(jié)
1.如果程序內(nèi)存不足或者頻繁GC,很有可能存在內(nèi)存泄露情況,這時(shí)候就要借助Java堆Dump查看對(duì)象的情況。
2.要制作堆Dump可以直接使用jvm自帶的jmap命令
3.可以先使用jmap -heap命令查看堆的使用情況,看一下各個(gè)堆空間的占用情況。
4.使用jmap -histo:[live]查看堆內(nèi)存中的對(duì)象的情況。如果有大量對(duì)象在持續(xù)被引用,并沒有被釋放掉,那就產(chǎn)生了內(nèi)存泄露,就要結(jié)合代碼,把不用的對(duì)象釋放掉。
5.也可以使用jmap -dump:format=b,file=<fileName>命令將堆信息保存到一個(gè)文件中,再借助jhat命令查看詳細(xì)內(nèi)容
6.在內(nèi)存出現(xiàn)泄露、溢出或者其它前提條件下,建議多dump幾次內(nèi)存,把內(nèi)存文件進(jìn)行編號(hào)歸檔,便于后續(xù)內(nèi)存整理分析。
7.在用cms gc的情況下,執(zhí)行jmap -heap有些時(shí)候會(huì)導(dǎo)致進(jìn)程變T,因此強(qiáng)烈建議別執(zhí)行這個(gè)命令,如果想獲取內(nèi)存目前每個(gè)區(qū)域的使用狀況,可通過jstat -gc或jstat -gccapacity來拿到。
Error attaching to process: sun.jvm.hotspot.debugger.DebuggerException: Can’t attach to the process
在ubuntu中第一次使用jmap會(huì)報(bào)錯(cuò):Error attaching to process: sun.jvm.hotspot.debugger.DebuggerException: Can't attach to the process,這是oracla文檔中提到的一個(gè)bug:http://bugs.java.com/bugdatabase/view_bug.do?bug_id=7050524,解決方式如下:
echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope 該方法在下次重啟前有效。
永久有效方法 sudo vi /etc/sysctl.d/10-ptrace.conf 編輯下面這行: kernel.yama.ptrace_scope = 1 修改為: kernel.yama.ptrace_scope = 0 重啟系統(tǒng),使修改生效。
windows查看進(jìn)程號(hào)方法:
由于任務(wù)管理器默認(rèn)的情況下是不顯示進(jìn)程id號(hào)的,所以可以通過如下方法加上。
ctrl+alt+del打開任務(wù)管 理器,選擇‘進(jìn)程’選項(xiàng)卡,點(diǎn)‘查看’->''選擇列''->加上''PID'',就可以了。當(dāng)然還有其他很好的選項(xiàng)。
總結(jié)
以上是生活随笔為你收集整理的java命令--jmap命令使用(查找内存泄漏对象)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: js/html 在线格式化工具
- 下一篇: 维基百科镜像处理