JVM內存溢出分析-實戰JVM(二)

JVM規範規定,除了程序計數器,虛擬機其餘內存區域均會發生內存溢出的可能,OutOfMemoryError(OOM) java

原文地址:http://www.begincode.net/blog/62  個人網站,歡迎你們多提意見 eclipse

本文目的: jvm

    一、經過代碼人爲形成OOM,讓你們跟了解JVM運行時各區存儲的內容。 函數

    二、經過demo讓你們實際開發過程當中,可以根據異常判斷是那個內存區域發生的溢出, 工具

    三、讓你們瞭解到什麼樣的代碼會產生OOM,開發中可以儘可能規避。 測試

前提: 網站

     先和你們介紹一下eclipse如何設置JVM參數,Xms 最小堆內存,Xmx最大堆內存, spa

      HeapDumpOnOutOfMemoryError:發生內存溢出時生成堆轉儲快照 操作系統

1、JAVA堆內存溢出 .net

 代碼實例,來自<<深刻理解JVM虛擬機>>

public class TestOOM {
	static class OOMObject{
		
	}
	public static void main(String[] args) {
		List<OOMObject> list = new ArrayList<OOMObject>();
		while(true){
			list.add(new OOMObject());
		}
	}

}

運行結果以下,發生內存溢出,在OutOfMemoryError後面會跟着 Java heap space 提示是堆內存溢出,

同時生成 java_pid10308.hprof 文件

該文件能夠用分析工具MAT進行分析,安裝連接http://www.begincode.net/blog/45 也能夠用其餘工具,

java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid10308.hprof ...
Heap dump file created [27883798 bytes in 0.497 secs]

經過工具能夠分析是內存泄露仍是內存溢出,若是不存在泄露,那就是存在着不少對象實例沒法回收,能夠經過分析查看是那些對象,是否必須存活,若是必須存活在考慮適當調整JVM堆參數,如Xmx Xms等在之後的文章中會在此介紹。

2、虛擬機棧和本地方棧溢出(棧溢出)

    一、虛擬機棧

   虛擬機棧溢出,理論上分爲兩種,一種是線程請求的棧深度大於虛擬機容許的最大深度,另一種是申請的空間不足。

   由於虛擬機棧記錄的是局部變量(方法變量)和函數調用棧針,則產生堆棧溢出通常是函數調用深度,如遞歸類或者

    方法A調用方法B,方法B調用方法C這樣調用深度超過了虛擬機容許的最大深度,

    JVM參數設置爲以下,Xss128k  Xss是堆棧大小

-Xms20m -Xmx20m -Xss128k -XX:+HeapDumpOnOutOfMemoryError

 demo以下

public class TestOOM {
	static int stackIndex = 0;
	public   void testStackOverFlow(){
		stackIndex++;
		testStackOverFlow();
	}

	public static void main(String[] args) throws Throwable  {
		try{
			TestOOM oom = new TestOOM();
			oom.testStackOverFlow();
		}catch(Throwable e){
			System.out.println("堆棧深度(迭代次數):"+stackIndex);
			throw e;
		}
	}
}

執行結果,堆棧深度達到983,堆棧溢出,並會給出具體是類,方法,發生的錯誤

堆棧深度(迭代次數):983
Exception in thread "main" java.lang.StackOverflowError
	at zgwx.TestOOM.testStackOverFlow(TestOOM.java:9)
	at zgwx.TestOOM.testStackOverFlow(TestOOM.java:10)
相同參數狀況下若是修改遞歸的方法,在方法內建立幾個變量你們再看下結果。
public   void testStackOverFlow(){
		stackIndex++;
		int str = 12;
		int str2 = 12;
		int str3 = 12;
		int str4 = 12;
		int str5 = 12;
		int str6 = 12;
		int str7 = 12;
		int str8 = 12;
		testStackOverFlow();
	}

執行結果以下,迭代次數明顯減小,說明局部變量佔用了堆棧的空間

堆棧深度(迭代次數):579
Exception in thread "main" java.lang.StackOverflowError
	at zgwx.TestOOM.testStackOverFlow(TestOOM.java:9)
	at zgwx.TestOOM.testStackOverFlow(TestOOM.java:18)

    二、本地方法棧,本地方法棧能夠經過建立線程的方式來實現溢出,由於java線程是映射到操做系統內核上,因此線程會調用本地方法,形成本地方法棧的溢出

   本機環境沒測試出來,機器卡死了,你們能夠本身試試儘可能多建立線程,就會撐爆本地方法棧

   下面是找來的例子,沒見到效果,都死卡死機了結

public class Test {
	private void runAlways(){
		while(true){
			
		}
	}
	public void createThread(){
		while(true){
			Thread thread = new Thread(new Runnable(){
				public void run() {
					runAlways();
				}
				
			});
			thread.start();
		}
	}
	public static void main(String[] args) {
		Test test = new Test();
		test.createThread();
	}
	}

3、直接本機內存溢出

    本機內存溢出能夠無限制申請空間便可,用nio的申請緩衝區方式

public static void main(String[] args) {
		List list = new ArrayList();
		while(true){
			ByteBuffer byteBuffer = ByteBuffer.allocateDirect(1024*2048);
			list.add(byteBuffer);
		}
	}

執行結果以下,OutOfMemoryError後面的提示,Direct buffer memory 說明了直接緩衝區,

Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory
	at java.nio.Bits.reserveMemory(Bits.java:658)
	at java.nio.DirectByteBuffer.<init>(DirectByteBuffer.java:123)

4、方法區(永久代)溢出

    方法區存儲的是加載的類信息,常量,咱們就循環建立字符串常量,讓方法區溢出

    爲了儘快溢出,jvm參數設置永久代參數5M: -XX:PermSize=5m  -XX:MaxPermSize=5m

    代碼以下:

public static void main(String[] args) {
		List list = new ArrayList();
		int i = 0;
		while(true){
			list.add((String.valueOf(i++)).intern());
		}
	}

 運行結果以下:OutOfMemoryError後面提示 PermGen space ;改代碼在jdk6及如下版本可以報出以下異常,jdk7高版本及以上部分jvm已經逐漸開始取消永久代的緣由,只會報出堆內存異常

Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
	at java.lang.String.intern(Native Method)
	at com.TestSocket.main(TestSocket.java:12)
相關文章
相關標籤/搜索