堆溢出
堆中一般存放對象、數組等大對象,當堆中的對象達到堆的最大容量限制後,就會產生內存溢出
JVMargs:-Xms20M -Xmx20M -XX:+HeapDumpOnOutOfMemoryError
public class HeapOOM {
static class OOMObject{}
public static void main(String[] args) throws InterruptedException {
List<OOMObject>list=new ArrayList<OOMObject>();
while(true) {
list.add(newOOMObject());
}}
}
Jdk1.7中,常量池被移到了堆中,因此也會因爲過多常量導致溢出
int i=0;
while (true) {
list.add(String.valueOf(i++));//會導致堆溢出
}
棧溢出
所有棧的總空間無法規定,所以棧的總空間≈機器內存-堆內存-方法區1、StackOverflowError:線程請求的深度大於虛擬機所允許的最大深度
單線程操作中,只能產生StackOverflowError異常
使用-Xss參數減少單個棧內存的容量,結果拋出StackOverflowError異常,且異常輸出時堆棧深度相應縮小
再增大本地變量佔用空間(增大棧幀中本地變量表的長度),結果拋出StackOverflowError異常時,堆棧深度再次縮小
public class StackSOF {
private int stacklength=1;//模擬棧的深度(棧幀數量)
public void stackLeak() throws InterruptedException{
//int a=500;
//int b=400;
//int c=600;
//int d=900;
Thread.sleep(1);
stacklength++;
stackLeak();
}
public static void main(String[] args) {
StackSOF oom=new StackSOF();
try {
oom.stackLeak();
} catch (Throwable e) {
System.out.println("stack length:"+oom.stacklength);
e.printStackTrace();
}
}
}
當定義上述a、b、c、d四個變量時,因爲棧幀變大,但棧的容量不變(128k),所以棧的深度變小(約2481→1819)。棧深度在大多情況下達到1000~2000是沒有問題的
2、OutOfMemoryError:在擴展棧時無法申請到足夠的內存空間
通過不斷產生線程的方式可以產生內存溢出,並且爲每個棧分配的內存越大,越容易溢出
每個線程分配到的棧容量越大,可以建立的線程數量就越少,建立線程時就越容易把剩下的內存耗盡。
通過減少內存的方式來解決內存溢出:
如果建立過多的線程導致內存溢出,在不能減少線程數或者更換64位虛擬機的情況下,只能通過減少棧容量或減少最大堆容量來換取更多的線程
方法區溢出
1、常量池導致方法區溢出
Jdk1.6時,常量池在方法區,因此new過多的字符串常量會導致常量池溢出
List<String> list=new ArrayList<String>();
long i=0;
while(true){
list.add(String.valueOf(++i).intern());
}
Jdk1.7時,常量池在堆內,不會產生上述效果
2、Hibernate、Spring等加載時,都會用到CGLIb等字節碼技術,需要方法區的容量來保證動態創建的class,因此也可能導致方法區溢出