內存溢出分析總結

堆溢出

堆中一般存放對象、數組等大對象,當堆中的對象達到堆的最大容量限制後,就會產生內存溢出
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,因此也可能導致方法區溢出


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