JVM 异常分析

在java 虚拟机规范中描述了两种异常:

 

1.如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出 StackOverflowError异常

 

2.如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError

实例一: java堆溢出

package com.com.atguigu;


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


//java 内存溢出实例
public class HeapOOM {


static class OOMObject {
        }


public static void main(String[] args) {
List<OOMObject> list = new ArrayList<OOMObject>();
    while (true) {
     //这里不断的在堆中创建新的实例对象,把内存撑破了      
      list.add(new OOMObject());
                    }
        }
}

异常信息:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Arrays.java:3210)
    at java.util.Arrays.copyOf(Arrays.java:3181)
    at java.util.ArrayList.grow(ArrayList.java:261)
    at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)
    at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)
    at java.util.ArrayList.add(ArrayList.java:458)
    at com.com.atguigu.HeapOOM.main(HeapOOM.java:15)

实例二:java 虚拟机栈和本地方法栈溢出

 

虚拟机栈溢出

package com.atguigu.newproject;

/**
* VM Args: Xss2M
*/

public class JavaVMStackSOF {
     private  int  stackLength = 1;
     public void stackLeak() {
          stackLength++;
          System.out.println("执行次数 " + stackLength);
          stackLeak();
     }
     public static void main(String[] args) {
          JavaVMStackSOF me  = new JavaVMStackSOF();
          try {
              //每次调用stackLeak() 方法都会往虚拟机栈中压入一个栈帧,无限递归,就会一直进行压栈操作
              //这样某个时间栈的深度会大于会大于虚拟机栈允许的最大深度
              me.stackLeak();
          } catch (Exception e) { 
              System.out.println("stack length :" + me.stackLength);
              // TODO Auto-generated catch block
              throw e;
          }
     }
}

创建线程导致内存溢出:

package com.com.atguigu;

public class JavaVMStackOOM {

private void dontStop() {
while (true){

    }
}

public void StackLeakByThread() {
     while (true) {
          Thread thread = new Thread(new Runnable() {
             public void run() {
                 dontStop();
     }
});
            thread.start();
      }
}

    public static void main(String[] args) {
        JavaVMStackOOM oom = new JavaVMStackOOM();
          oom.StackLeakByThread();
     }
}

注意:上面的代码运行时,由于windows平台的虚拟机中,java的线程是映射到操作系统的内核线程上的,所以上述代码执行时有较大风险,可能会导致操作系统假死。

实例三:运行时常量池导致的内存溢出异常

package com.com.atguigu;

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

/**
* VM Args: -XX:PermSize=10M -XX:MaxPermSize=10M
*/
public class RuntimeConstantPoolOOM {

   public static void main(String[] args) {
      //使用List保持着常量池引用,避免Full GC 回收常量
      List<String> list = new ArrayList<String>();
      //10MB 的PermSize 在integer 范围内足够产生OOM了
       int i = 0;
       while (true) {
         //itern() 方法表示如果常量池中已经包含了一个等于此String对象的字符串,则返回池中这个串的String对象,否则,               //将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。
         list.add(String.valueOf(i++).intern());  
       }
    }
}

注意: 从运行结果可以看到,运行时常量池溢出,在OutOfMemoryError 后面跟随的提示信息是“PermGen space”,说明运行时常量池属于方法区的一部分。

查看虚拟机设置:

C:\Users\gezongyang>Java -XX:PermSize=10M -version
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=10M; support was removed in 8.0
java version "1.8.0_71"
Java(TM) SE Runtime Environment (build 1.8.0_71-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.71-b15, mixed mode)

这里显示,PermSize=10M; support was removed in 8.0 这种设置已经在java8中不能生效了

实例四:方法区内存溢出

注意:-XX:PermSize=10M -XX:MaxPermSize=10M  这两个参数java8已经不支持了

package com.com.atguigu;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
* VM Args: -XX:PermSize=10M -XX:MaxPermSize=10M
*/
public class JavaMethodAreaOOM {

public static void main(final String[] args) {

          while (true) {
                 Enhancer enhancer = new Enhancer();
                 enhancer.setSuperclass(OOMObject.class);
                  enhancer.setUseCache(false);
                   enhancer.setCallback(new MethodInterceptor() {
                           public Object intercept(Object o, Method method, Object[] objects, MethodProxy proxy) throws      Throwable {
                     return proxy.invokeSuper(objects, args);
       }
  });
  }
}

static class OOMObject {

}
}

以上使用了CGlib包,依赖如下

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.1</version>
</dependency>

原因分析:一个类如果要被垃圾回收器回收掉,判定条件十分苛刻。这里使用CGlib字节码增强,动态生成大量Class。

实例五:本机直接内存溢出

package com.com.atguigu;

import sun.misc.Unsafe;

import java.lang.reflect.Field;

/**
* VM Args: -Xmx20m -XX:MaxDirectMemorySize=10M
*/
public class DirectMemoryOOM {

private static final int _1MB = 1024 * 1024;

public static void main(String[] args) throws IllegalAccessException {
        Field field = Unsafe.class.getDeclaredFields()[0];
        field.setAccessible(true);
        Unsafe unsafe = (Unsafe) field.get(null);
        while (true) {
            unsafe.allocateMemory(_1MB);
        }
    }
}

异常:

Exception in thread "main" java.lang.OutOfMemoryError
    at sun.misc.Unsafe.allocateMemory(Native Method)
    at com.com.atguigu.DirectMemoryOOM.main(DirectMemoryOOM.java:19)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

独行客-编码爱好者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值