zoukankan      html  css  js  c++  java
  • 从几个sample来学习JAVA堆、方法区、JAVA栈和本地方法栈

    最近在看《深入理解Java虚拟机》,书中给了几个例子,比较好的说明了几种OOM(OutOfMemory)产生的过程,大部分的程序员在写程序时不会太关注Java运行时数据区域的结构:

    感觉有必要通过几个实在的例子来加深对这几个区域的了解

    1)Java堆

    所有对象的实例分配都在Java堆上分配内存,堆大小由-Xmx和-Xms来调节,sample如下所示:

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

    并且能自动生成Dump。

    2)方法区

    方法区是存放虚拟机加载类的相关信息,如类、静态变量和常量,大小由-XX:PermSize和-XX:MaxPermSize来调节,类太多有可能撑爆永久带:

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

    静态变量或常量也会有可能撑爆方法区:

    1. public class ConstantOOM { 
    2.  
    3.     /**
    4.      * @param args
    5.      */ 
    6.     public static void main(String[] args) { 
    7.         // TODO Auto-generated method stub 
    8.         List<String> list = new ArrayList<String>(); 
    9.         int i=0; 
    10.         while(true){ 
    11.             list.add(String.valueOf(i++).intern()); 
    12.         } 
    13.     } 
    14.  
    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.  
    3. public class StackOOM { 
    4.  
    5.     /**
    6.      * @param args
    7.      */ 
    8.      
    9.     private int stackLength = 1; 
    10.      
    11.     public void stackLeak(){ 
    12.         stackLength++; 
    13.         stackLeak(); 
    14.     } 
    15.      
    16.     public static void main(String[] args) throws Throwable{ 
    17.         // TODO Auto-generated method stub 
    18.         StackOOM oom = new StackOOM(); 
    19.         try{ 
    20.             oom.stackLeak(); 
    21.         }catch(Throwable err){ 
    22.             System.out.println("Stack length:" + oom.stackLength); 
    23.             throw err; 
    24.         } 
    25.          
    26.     } 
    27.  
    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.  
    3. public class StackOOM { 
    4.  
    5.     /**
    6.      * @param args
    7.      */ 
    8.      
    9.     private int stackLength = 1; 
    10.      
    11.     private void dontStop(){ 
    12.         while(true){ 
    13.             try{Thread.sleep(1000);}catch(Exception err){} 
    14.         } 
    15.     } 
    16.      
    17.     public void stackLeakByThread(){ 
    18.         while(true){ 
    19.             Thread t = new Thread(new Runnable(){ 
    20.  
    21.                 @Override 
    22.                 public void run() { 
    23.                     // TODO Auto-generated method stub 
    24.                     dontStop(); 
    25.                 } 
    26.                  
    27.             }); 
    28.             t.start(); 
    29.             stackLength++; 
    30.         } 
    31.     } 
    32.      
    33.     public static void main(String[] args) throws Throwable{ 
    34.         // TODO Auto-generated method stub 
    35.         StackOOM oom = new StackOOM(); 
    36.         try{ 
    37.             oom.stackLeakByThread(); 
    38.         }catch(Throwable err){ 
    39.             System.out.println("Stack length:" + oom.stackLength); 
    40.             throw err; 
    41.         } 
    42.          
    43.     } 
    44.  
    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栈和本地方法栈

  • 相关阅读:
    [Linux]软件目录
    [Linux]查看Linux内核及发行版本
    [S7706]华为ACL
    [S7706]华为配置DHCP
    QML-密码管理器
    QML-AES加解密小工具
    LaTex中文article模板(支持代码、数学、TikZ)
    Memo-Tech
    VIM学习笔记
    CodeForces 674C Levels and Regions
  • 原文地址:https://www.cnblogs.com/hzhtracy/p/4574823.html
Copyright © 2011-2022 走看看