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栈和本地方法栈

  • 相关阅读:
    关于celery踩坑
    关于git的分批提交pull requests流程
    SymGAN—Exploiting Images for Video Recognition: Heterogeneous Feature Augmentation via Symmetric Adversarial Learning学习笔记
    AFN—Larger Norm More Transferable: An Adaptive Feature Norm Approach for Unsupervised Domain Adaptation学习笔记
    Learning to Transfer Examples for Partial Domain Adaptation学习笔记
    Partial Adversarial Domain Adaptation学习笔记
    Partial Transfer Learning with Selective Adversarial Networks学习笔记
    Importance Weighted Adversarial Nets for Partial Domain Adaptation学习笔记
    Exploiting Images for Video Recognition with Hierarchical Generative Adversarial Networks学习笔记
    improved open set domain adaptation with backpropagation 学习笔记
  • 原文地址:https://www.cnblogs.com/hzhtracy/p/4574823.html
Copyright © 2011-2022 走看看