實戰Java虛擬機之一“堆溢出處理”

從今天開始,我會發5個關於java虛擬機的小系列:

  • 實戰Java虛擬機之一“堆溢出處理”

  • 實戰Java虛擬機之二“虛擬機的工作模式”

  • 實戰Java虛擬機之三“G1的新生代GC”

  • 實戰Java虛擬機之四“禁用System.gc()”

  • 實戰Java虛擬機之五“開啓JIT編譯”

下面說說【實戰Java虛擬機之一“堆溢出處理”】

在Java程序的運行過程中,如果堆空間不足,則有可能拋出內存溢出錯誤(Out Of Memory),簡稱爲OOM。如下文字顯示了典型的堆內存溢出:

  1. Exception in thread “main” java.lang.OutOfMemoryError: Java heap space  

  2. at geym.zbase.ch3.heap.DumpOOM.main(DumpOOM.java:20)  


一旦發生這類問題,系統就會被迫退出。如果發生在生產環境,可能會引起嚴重的業務中斷。爲了能夠不斷改善系統,避免或減少這類錯誤的發生,需要在發生錯誤時,獲得儘可能多的現場信息,以幫助研發人員排查現場問題。Java虛擬機提供了參數-XX:+HeapDumpOnOutOfMemoryError,使用該參數,可以在內存溢出時導出整個堆信息。和它配合使用的還有-XX:HeapDumpPath,可以指定導出堆的存放路徑。


【示例3-4】以下代碼合計分配了25M內存空間。

  1. public class DumpOOM {  

  2.  public static void main(String[] args) {  

  3.  Vector v=new Vector();  

  4.   for(int i=0;i<25;i++)  

  5.    v.add(new byte[1*1024*1024]);  

  6.  }  

  7. }  


使用如下參數執行上述代碼:

-Xmx20m -Xms5m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=d:/a.dump

顯然20M堆空間不足以容納25M內存,系統比如發生內存溢出,在發生錯誤後,控制檯輸出如下:

  1. java.lang.OutOfMemoryError: Java heap space  

  2. Dumping heap to d:/a.dump …  

  3. Heap dump file created [23067302 bytes in 0.160 secs]  

  4. Exception in thread “main” java.lang.OutOfMemoryError: Java heap space  

  5. at geym.zbase.ch3.heap.DumpOOM.main(DumpOOM.java:19)  


可以看到,虛擬機將當前的堆導出,並保存到D:/a.dump文件下。使用MAT等工具打開該文件進行分析,如圖所示,可以很容易地找到這些byte數組和保存它們的Vector對象實例。有關MAT等工具的使用,可以參閱《實戰Java虛擬機-jvm故障診斷與性能優化》第7章。

jvm1

除了在發生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目錄,進行嘗試。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章