java堆用於存儲對象實例,只要不斷建立對象,而且保證GC Roots(一直GC回收算法)到對象之間有可達路徑來避免垃圾回收機制清除這些對象,那麼對象在對象數量到達最大堆的容量限制後就會產生內存溢出異常。java
java堆異常是實際應用常見的內存溢出異常狀況。當出現JAVA堆內存溢出狀況時,異常堆棧信息「java,lang.OutOfMemoryError」 跟着進一步提示「java heap space」。算法
使用內存分析工具對堆內存進行分析,次數使用的是Eclipse memory Analyzer 獨立安裝。bash
測試代碼:多線程
public class OomError {
static class OOMObject{
}
public static void main(String[] args) {
List<OOMObject> lists = new ArrayList<>();
int i = 1;
while (true){
i++ ;
if(i<1000000){
lists.add(new OOMObject());
}
System.out.println("對象初始化完成");
}
}
}
複製代碼
內存泄漏分析: 工具
因爲GC Roots引用鏈的信息,對象沒有被回收,經過分析能夠準肯定位內存泄漏代碼的位置。測試
public class OomError {
private int stackLen = 1;
public void stackLeak(){
stackLen ++ ;
stackLeak();
}
public static void main(String[] args) {
OomError oom = null;
try{
oom = new OomError();
oom.stackLeak();
}catch (Throwable e){
e.printStackTrace();
System.out.println("棧的最大深度"+oom.stackLen);
}
}
}
}catch (Throwable e){
e.printStackTrace();
System.out.println("棧的最大深度"+oom.stackLen);
}
}
}
複製代碼
異常信息:ui
java.lang.StackOverflowError
at com.haihang.exception.OomError.stackLeak(OomError.java:12)
棧的最大深度16726
複製代碼
實驗證實:在單線程下內存沒法分配時,虛擬機都是拋出StackOverflowError異常。spa
在多線程下,經過減小最大的堆和減小棧容量來換取更多的線程。線程
public class OomError {
public static void main(String[] args) {
//保持對象的引用防止GC
List<String> lists =new ArrayList<>();
int i=0;
while(true){
//intern 爲本地方法,做用是先從常量池中查找字符,若是不存在將字符放入常量池
lists.add(String.valueOf(i++).intern());
}
}
}
複製代碼
異常信息:code
java.lang.OutOfMemoryError:Permgen space
複製代碼
在HotSpot虛擬機中Permgen space 屬於堆中的永久代。
圖片相同的代碼邏輯返回的結果倒是不同,由於在jdk1.7之後的intern不在複製,只是在常量池中記錄對象的引用,所以intern返回的引用於StringBuilder建立的字符串實例是同一個,因此相同;str2返回false的緣由是「java」這個字符在執行toString以前已經出現過,不符合「首次出現」的原則,而計算機軟件是首次出現的,所以返回true。