一:堆內存溢出
Java創建的對象一般都是分配在堆中,如果是由於過期對象沒能回收(內存泄漏)或者對象過多導致放不下(內存溢出),一般報錯:
Exception in thread \"main\" java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:2760) at java.util.Arrays.copyOf(Arrays.java:2734) at java.util.ArrayList.ensureCapacity(ArrayList.java:167) at java.util.ArrayList.add(ArrayList.java:351) at test.java.VM.OOM.HeapOOM.main(HeapOOM.java:19)
解決這部分的異常,重點是通過內存映像分析工具分析堆的轉儲快照,確定異常是由於內存泄漏還是內存溢出導致的。
如果是內存泄漏導致的,則進一步查看泄漏對象到GCRoots的引用鏈,觀察泄漏對象是通過怎樣的路徑與GCRoots相關聯並導致垃圾回收器無法回收的;
如果是內存溢出導致的,則檢測堆的大小參數(Xmx、Xms)看看能否再調大,檢測是否有某些對象生命周期過長。
二:方法區溢出
方法區主要存放類的信息、靜態變量、常量池等,當常量池溢出或者不停地有類動態創建並加載時,方法區也能產生OOM。
報錯信息:
Exception in thread \"main\" java.lang.OutOfMemoryError: PermGen space
拓展:String.intern():如果字符串常量池已經包含一個等於此string對象的字符串,則返回該字符串;否則,將次string對象的內容加入到常量池中,並返回該對象的引用。
三:棧溢出(虛擬機棧、本地方法棧)
棧的異常有兩種:
JVM在執行方法時就會創建方法棧,方法的遞歸、調用等使得其他方法不停地入棧,其他方法執行完畢就會彈出棧幀。當一個方法棧的深度大於JVM所允許的深度時就會報StackOverFlow;一般,出現StackOverFlow時就要檢查代碼是否有無窮遞歸的情況出現了。
stack length:1007Exception in thread \"main\" java.lang.StackOverflowError at test.java.VM.OOM.JavaVMStackOF.stackLeak(JavaVMStackOF.java:13) at test.java.VM.OOM.JavaVMStackOF.stackLeak(JavaVMStackOF.java:14)
棧空間擴展時沒有足夠的內存則報OutOfMemory。
四:本地直接內存溢出
直接內存可以通過 -XX:MaxDirectMemorySize指定。如果本地直接內存溢出,我們可以發現堆轉儲快照中無明顯異常指示,並且快照文件很小,而程序中又使用了NIO等技術,則可以檢查是否直接內存溢出了。