JVM异常解析

 一.Java虚拟机栈和本地方法栈内存异常探究

     1.如果线程请求分配的栈容量超过Java虚拟机栈允许的最大容量时,Java虚拟机会抛出一个StackOverflowError异常

package com.stack.over;

/*
 * 构造自己的实例,不断递归调用自己,当递归的栈深度到达一定的程度,Java虚拟机就会抛出StackOverflowError异常
 * VM栈深度设置: -Xss128k     设置栈深度为128K
 */

public class JavaVmStackSOF {
    
	private int stackLength = 1;
	
	public void stackLeak(){
		stackLength++;
		stackLeak();
	}
	
	public static void main(String[] args) throws Throwable{
		// TODO Auto-generated method stub
        JavaVmStackSOF oom = new JavaVmStackSOF();
        try {
			oom.stackLeak();
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			System.out.println("stack length:" + oom.stackLength);
			throw e;
		}
	}

}

运行截图:

JVM异常解析_第1张图片


2.如果Java虚拟机栈可以动态扩展,并且扩展的动作已经尝试过,但是目前无法申请到足够的内存去完成扩展,或者在建立新的线程时,没有足够的内存去创建对应的虚拟机栈,那么Java虚拟机将会抛出一个OutOfMemoryError

package com.stack.over;

/*
 * 1.Java虚拟机栈设置成可以动态拓展,并且动态拓展已经尝试,仍然无法申请到足够的内存,Java虚拟机就会抛出异常
 * 2.Java虚拟机尝试建立新线程时,如果当前已经没有足够的内存去创建新 线程,或操作系统拒绝创建新线程,这时Java虚拟机也会抛出异常
 * 注意:此段代码运行将会创建很多线程,让系统变得十分卡慢,直到内存不足,终止运行
 */
public class JavaVmStackOOM {

	public void dontstop(){
		while(true){
			
		}
	}
	
	public void stackLeakByThread(){
		while(true){
			Thread thread = new Thread(new Runnable() {	
				@Override
				public void run() {
					// TODO Auto-generated method stub
					dontstop();
				}
			});
			thread.start();
		}
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
        JavaVmStackOOM oom = new JavaVmStackOOM();
        oom.stackLeakByThread();
	}

}

二.Java堆内存异常探究

   1.如果实际所需的堆超过了自动内存管理系统能提供的最大容量,那么Java虚拟机将会抛出一个OutOfMemoryError

package com.heap.over;

import java.util.ArrayList;
import java.util.List;

/*
 * 1.不断在Java堆中创建对象,并保证对象不会被内存回收,随着while的不断循环执行,对象会越来越多,直至超出Java堆的最大容量
 * 2.将JVM的内存参数设置在20M之内,Java堆发生溢出时,Java虚拟机会自动把当前Java堆的内存印象荡复到磁盘中,供后续调试分析: 
 *  -Xms20m  -Xmx20m  -XX:+HeapDumpOnOutOfMemoryError
 */
public class HeapOOM {

	public static class OOMObject{
		
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub
      List list = new ArrayList();
      
      while(true){
    	  list.add(new OOMObject());       //对象一直被List集合引用,保证不会被回收
      }
	}

}

截图:

JVM异常解析_第2张图片


三.Java常量池与方法区溢出异常

package com.constantPool.over;

import java.util.ArrayList;
import java.util.List;

/*
 * 运行时常量池溢出的代码
 * 把虚拟机的永久代内存限制起始10M,最大10M:  -XX:PermSize=10M -XX:MaxPermSize=10M
 * 1.不断循环,产生字符串常量,字符串常量会随整形数字i的增加而不断变化
 */
public class RuntimeConstantPoolOOM {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
	   //使用List保持着常量池引用,避免Full GC回收常量池行为
       List list = new ArrayList ();
       //10M的PermSize在Integer范围内足够产生OOM
       int i = 0 ;
       while(true){
    	   list.add(String.valueOf(i++).intern());       //随i增加不断变化
       }
	}
   
	//jdk1.7开始把字符串常量池罗列到Java堆中,即使这么多对象也不足够让内存撑爆,不会抛出异常,jdk1.6的永久代会抛异常
}



你可能感兴趣的:(深入理解Java虚拟机)