從今天開始,我會發5個關於java虛擬機的小系列:
- 實戰Java虛擬機之一“堆溢出處理”
- 實戰Java虛擬機之二“虛擬機的工作模式”
- 實戰Java虛擬機之三“G1的新生代GC”
- 實戰Java虛擬機之四“禁用System.gc()”
- 實戰Java虛擬機之五“開啟JIT編譯”
下面說說【實戰Java虛擬機之一“堆溢出處理”】
在Java程序的運行過程中,如果堆空間不足,則有可能拋出內存溢出錯誤(Out Of Memory),簡稱為OOM。如下文字顯示了典型的堆內存溢出:
- Exception in thread “main” java.lang.OutOfMemoryError: Java heap space
- at geym.zbase.ch3.heap.DumpOOM.main(DumpOOM.java:20)
一旦發生這類問題,系統就會被迫退出。如果發生在生產環境,可能會引起嚴重的業務中斷。為了能夠不斷改善系統,避免或減少這類錯誤的發生,需要在發生錯誤時,獲得盡可能多的現場信息,以幫助研發人員排查現場問題。Java虛擬機提供了參數-XX:+HeapDumpOnOutOfMemoryError,使用該參數,可以在內存溢出時導出整個堆信息。和它配合使用的還有-XX:HeapDumpPath,可以指定導出堆的存放路徑。
【示例3-4】以下代碼合計分配了25M內存空間。
- public class DumpOOM {
- public static void main(String[] args) {
- Vector v=new Vector();
- for(int i=0;i<25;i++)
- v.add(new byte[1*1024*1024]);
- }
- }
使用如下參數執行上述代碼:
-Xmx20m -Xms5m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/a.dump
顯然20M堆空間不足以容納25M內存,系統比如發生內存溢出,在發生錯誤后,控制台輸出如下:
- java.lang.OutOfMemoryError: Java heap space
- Dumping heap to d:/a.dump …
- Heap dump file created [23067302 bytes in 0.160 secs]
- Exception in thread “main” java.lang.OutOfMemoryError: Java heap space
- at geym.zbase.ch3.heap.DumpOOM.main(DumpOOM.java:19)
可以看到,虛擬機將當前的堆導出,並保存到D:/a.dump文件下。使用MAT等工具打開該文件進行分析,如圖所示,可以很容易地找到這些byte數組和保存它們的Vector對象實例。有關MAT等工具的使用,可以參閱《實戰Java虛擬機-jvm故障診斷與性能優化》第7章。
除了在發生OOM時可以導出堆信息外,虛擬機還允許在發生錯誤時執行一個腳本文件。該文件可以用於奔潰程序的自救、報警或者通知,也可以幫助開發人員獲得更多的系統信息,如完整的線程轉存(即Thread Dump或者Core Dump)文件。
這里給出一個在發生OOM時導出線程轉存的例子。准備printstack.bat腳本如下:
D:/tools/jdk1.7_40/bin/jstack -F %1 > D:/a.txt
以上腳本將會導出給定Java虛擬機進程的線程信息,並保存在D:/a.txt文件中。
使用如下參數執行上述代碼:
-Xmx20m -Xms5m “-XX:OnOutOfMemoryError=D:/tools/jdk1.7_40/bin/printstack.bat %p” -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/a.dump
在程序異常退出時,系統D盤下會生成新文件a.txt,里面保存着線程轉存信息。本例中,文件路徑“D:/tools/jdk1.7_40”為筆者的JDK按照目錄,讀者可以替換成自己的JAVA_HOME目錄,進行嘗試。
《實戰Java虛擬機》一書Q交流群:397196583