從幾個sample來學習Java堆,方法區,Java棧和本地方法棧

最近在看《深刻理解Java虛擬機》,書中給了幾個例子,比較好的說明了幾種OOM(OutOfMemory)產生的過程,大部分的程序員在寫程序時不會太關注Java運行時數據區域的結構: java

感受有必要經過幾個實在的例子來加深對這幾個區域的瞭解 程序員

1)Java堆 windows

全部對象的實例分配都在Java堆上分配內存,堆大小由-Xmx和-Xms來調節,sample以下所示: ide

  1. public class HeapOOM {
  2. static class OOMObject{}
  3. /**
  4. * @param args
  5. */
  6. public static void main(String[] args) {
  7. List<OOMObject> list = new ArrayList<OOMObject>();
  8. while(true){
  9. list.add(new OOMObject());
  10. }
  11. }
  12. }
public class HeapOOM {
	
	static class OOMObject{}

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

}

加上JVM參數-verbose:gc -Xms10M -Xmx10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError,就能很快報出OOM:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space spa

而且能自動生成Dump。 .net

2)方法區 線程

方法區是存放虛擬機加載類的相關信息,如類、靜態變量和常量,大小由-XX:PermSize和-XX:MaxPermSize來調節,類太多有可能撐爆永久帶: code

  1. public class MethodAreaOOM {
  2. static class OOMOjbect{}
  3. /**
  4. * @param args
  5. */
  6. public static void main(String[] args) {
  7. // TODO Auto-generated method stub
  8. while(true){
  9. Enhancer eh = new Enhancer();
  10. eh.setSuperclass(OOMOjbect.class);
  11. eh.setUseCache(false);
  12. eh.setCallback(new MethodInterceptor(){
  13. @Override
  14. public Object intercept(Object arg0, Method arg1,
  15. Object[] arg2, MethodProxy arg3) throws Throwable {
  16. // TODO Auto-generated method stub
  17. return arg3.invokeSuper(arg0, arg2);
  18. }
  19. });
  20. eh.create();
  21. }
  22. }
  23. }
public class MethodAreaOOM {
	
	static class OOMOjbect{}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		while(true){
			Enhancer eh = new Enhancer();
			eh.setSuperclass(OOMOjbect.class);
			eh.setUseCache(false);
			eh.setCallback(new MethodInterceptor(){

				@Override
				public Object intercept(Object arg0, Method arg1,
						Object[] arg2, MethodProxy arg3) throws Throwable {
					// TODO Auto-generated method stub
					return arg3.invokeSuper(arg0, arg2);
				}
				
			});
			eh.create();
		}
	}

}

加上永久帶的JVM參數:-XX:PermSize=10M -XX:MaxPermSize=10M,運行後會報以下異常:

Exception in thread "main" java.lang.OutOfMemoryError: PermGen space 對象

靜態變量或常量也會有可能撐爆方法區: blog

  1. public class ConstantOOM {
  2. /**
  3. * @param args
  4. */
  5. public static void main(String[] args) {
  6. // TODO Auto-generated method stub
  7. List<String> list = new ArrayList<String>();
  8. int i=0;
  9. while(true){
  10. list.add(String.valueOf(i++).intern());
  11. }
  12. }
  13. }
public class ConstantOOM {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		List<String> list = new ArrayList<String>();
		int i=0;
		while(true){
			list.add(String.valueOf(i++).intern());
		}
	}

}

一樣加上JVM參數:-XX:PermSize=10M -XX:MaxPermSize=10M,運行後報以下異常:

Exception in thread "main" java.lang.OutOfMemoryError: PermGen space

3)Java棧和本地方法棧

棧是存放線程調用方法時存儲局部變量表,操做,方法出口等與方法執行相關的信息,棧大小由Xss來調節,方法調用層次太多會撐爆這個區域,samples以下所示:

  1. package com.cutesource;
  2. public class StackOOM {
  3. /**
  4. * @param args
  5. */
  6. private int stackLength = 1;
  7. public void stackLeak(){
  8. stackLength++;
  9. stackLeak();
  10. }
  11. public static void main(String[] args) throws Throwable{
  12. // TODO Auto-generated method stub
  13. StackOOM oom = new StackOOM();
  14. try{
  15. oom.stackLeak();
  16. }catch(Throwable err){
  17. System.out.println("Stack length:" + oom.stackLength);
  18. throw err;
  19. }
  20. }
  21. }
package com.cutesource;

public class StackOOM {

	/**
	 * @param args
	 */
	
	private int stackLength = 1;
	
	public void stackLeak(){
		stackLength++;
		stackLeak();
	}
	
	public static void main(String[] args) throws Throwable{
		// TODO Auto-generated method stub
		StackOOM oom = new StackOOM();
		try{
			oom.stackLeak();
		}catch(Throwable err){
			System.out.println("Stack length:" + oom.stackLength);
			throw err;
		}
		
	}

}

設置JVM參數:-Xss128k,報出異常:

Exception in thread "main" java.lang.StackOverflowError

打印出Stack length:1007,這裏能夠看出,在個人機器上128k的棧容量能承載深度爲1007的方法調用。固然報這樣的錯不多見,通常只會出現無限循環的遞歸中,另外,線程太多也會佔滿棧區域:

  1. package com.cutesource;
  2. public class StackOOM {
  3. /**
  4. * @param args
  5. */
  6. private int stackLength = 1;
  7. private void dontStop(){
  8. while(true){
  9. try{Thread.sleep(1000);}catch(Exception err){}
  10. }
  11. }
  12. public void stackLeakByThread(){
  13. while(true){
  14. Thread t = new Thread(new Runnable(){
  15. @Override
  16. public void run() {
  17. // TODO Auto-generated method stub
  18. dontStop();
  19. }
  20. });
  21. t.start();
  22. stackLength++;
  23. }
  24. }
  25. public static void main(String[] args) throws Throwable{
  26. // TODO Auto-generated method stub
  27. StackOOM oom = new StackOOM();
  28. try{
  29. oom.stackLeakByThread();
  30. }catch(Throwable err){
  31. System.out.println("Stack length:" + oom.stackLength);
  32. throw err;
  33. }
  34. }
  35. }
package com.cutesource;

public class StackOOM {

	/**
	 * @param args
	 */
	
	private int stackLength = 1;
	
	private void dontStop(){
		while(true){
			try{Thread.sleep(1000);}catch(Exception err){}
		}
	}
	
	public void stackLeakByThread(){
		while(true){
			Thread t = new Thread(new Runnable(){

				@Override
				public void run() {
					// TODO Auto-generated method stub
					dontStop();
				}
				
			});
			t.start();
			stackLength++;
		}
	}
	
	public static void main(String[] args) throws Throwable{
		// TODO Auto-generated method stub
		StackOOM oom = new StackOOM();
		try{
			oom.stackLeakByThread();
		}catch(Throwable err){
			System.out.println("Stack length:" + oom.stackLength);
			throw err;
		}
		
	}

}

報出異常:Exception in thread "main" java.lang.OutOfMemoryError:unable to create new native thread

不過在windows上運行這個例子要當心,會出現系統假死的狀況,有可能須要重啓機器才行。

以上幾個例子雖然比較簡單,但能很好幫助普通的程序員更加直觀的瞭解Java堆方法區Java棧和本地方法棧

相關文章
相關標籤/搜索