jvm的框架知識了解之后,實際的項目里發生了oom異常的話,怎么獲取以及分析異常信息后怎么分析呢。
這里稍微做一下歸納。
第一步,首先通過下面兩個方法的任何一種,把發生oom時的heap信息dump下來。
有兩個方法,通過設置可以把oom時的dump信息獲取到:
1)方法1:在jvm的啟動參數里添加如下命令
-xx:+heapdumponoutofmemoryerror
2)方法2:在jdk的安裝目錄下,找到bin目錄,然后雙擊執行"jvisualvm.exe"
執行程序之后,在視圖里可以看到正在執行的java程序和java線程id(pid:xxx)。
右鍵選中"在oom時生成dump"。
第二步,執行如下代碼(本例使用方法1。如果使用方法2時需要先執行代碼,再在jvirtualvm中選中java程序設置oom時生成dump):
代碼的意義是每一次創建一個1*1024*1024大小的int數組。在while中循環,引起heap的outofmemory異常發生。
有一個小知識點共享下,map進行containskey的處理時,key如果是javabean對象,判斷時使用的是對象的引用。所以每次判斷都是新的對象。
最好key的數據類型定義為值類型等(string作為key時使用常量字符串對string賦值如string key ="key",不要用string key = new string(“key”)的形式,這樣又變成了一個引用對象了)。
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
|
package com.chong.studyparalell.jvm.heap; import java.util.hashmap; import java.util.map; public class heapleakage { static class mapkey{ integer key; mapkey(integer key){ this .key = key; } } public static void main(string []args){ map<mapkey,integer[]> localmap = new hashmap(); while ( true ){ for ( int i = 0 ;i< 10 ;i++){ try { thread.sleep( 100 ); } catch (exception e){ e.printstacktrace(); } mapkey mapkey = new mapkey( new integer(i)); if (!localmap.containskey(mapkey)){ localmap.put(mapkey, new integer[ 1 * 1024 * 1024 ]); } } } } } |
日志如下:
1
2
3
4
5
6
|
javagent: call premain instrumentation for class sizeof java.lang.outofmemoryerror: java heap space dumping heap to java_pid31512.hprof ... heap dump file created [ 491663234 bytes in 0.930 secs] exception in thread "main" java.lang.outofmemoryerror: java heap space at com.chong.studyparalell.jvm.heap.heapleakage.main(heapleakage.java: 38 ) |
第三步,在項目的classpath目錄下確認"java_pidxxx.hprof"文件是否存在,正常情況下應該存在的。
在jvirtualvm中,點擊"文件"->"裝入"->選中上述hprof文件。
點擊“類”tab頁,通過"大小"排序,可以看出java.lang.integer占用了99%以上的空間。
雙擊這一行,可以進入進去看到,各個integer的具體內容。這里的目的是發生oom,所以integer的內容沒有設值,進去可以發現值都是null。
那么實際的項目里,可以觀看發生問題線程里哪些對象的一直是活著的,并且size遠遠超出預期,重點分析這些可疑對象。推測的方向:是否在循環里大量的實例化對象,加載db數據時一次加載了大量的數據,以及是否發生了內存泄露(如長生命周期的map和set,list中一直保存在大量的不再使用的對象引用。),以及靜態變量的使用等。
后記:
通過這幾天的jvm復習,以及oom發生時的dump分析,再次做項目時,頭腦會更清晰一些。^-^
jvm告一段落了,接下來會發一些跟springboot和redis相關的學習心得。
原文鏈接:http://www.cnblogs.com/chongpf/p/7677973.html