常见JVM错误代码示例

2018-11-3 / 0评 / Java

一、常见JVM异常示例代码
package com.houxr.jvm.study;
import com.google.common.collect.Lists;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
 * jvm test
 * 需要设置 VM options : -Xms1m -Xmx1m -XX:MaxMetaspaceSize=5M
 * https://blog.csdn.net/soonfly/article/details/70147205
 * @author houxiurong
 * @date 2018-11-01
 */
public class JvmTest extends ClassLoader {
    /**
     * List是动态增长的,因此容量不够了,就会扩容,一旦空闲内存分配完毕,请求不到其他内存,就抛出OutOfMemoryError。
     * <p>
     * 模拟OutOfMemoryError 堆溢出错误
     * java.lang.OutOfMemoryError: Java heap space
     */
    public static void outOfMemoryError() {
        ArrayList list = Lists.newArrayList();
        while (true) {
            list.add(new JvmTest());
        }
    }
    /**
     * 不断往堆中塞新增的StringBuffer对象,堆满了就直接溢出了
     * Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
     */
    public static void heapOverFlow() {
        int count = 10000;
        int size = 0;
        while (true) {
            StringBuffer buffer = new StringBuffer();
            for (int i = 0; i < count; i++) {
                buffer.append(i);
            }
            System.out.println("=======================" + (++size));
        }
    }
    /**
     * 栈溢出错误
     * 程序详解:
     * 执行main函数会创建一个线程,同时创建一个虚拟机栈(栈内存)
     * 调用JvmTest.stackOverflowError()时,会对 stackOverflowError()进行压栈操作,将 stackOverflowError()运行期数据的数据集
     * 保存到栈帧(Stack Frame)(如果main方法里面调用多个方法,会执行多个压栈操作)。
     * stackOverflowError()递归调用时,都会产生一个新的栈帧区块,这时就会连续的产生新的栈帧区块
     * 当栈内存超过系统配置的栈内存-Xss:2048,就会出现java.lang.StackOverflowError异常.这也是为什么对于需要谨慎使用递归调用的原因!
     * Stack length:11131
     * <p>
     * Exception in thread "main" java.lang.StackOverflowError
     */
    public void stackOverflowError() {
        STACK_COUNT++;
        stackOverflowError();
    }
    private Integer STACK_COUNT = 1;
    /***
     * 运行时常量池导致内存溢出
     * JDK1.7 Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
     * JDK1.8 CMS Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
     */
    public static void runtimeConstantPoolOOM1() {
        //List保持常量池引用,避免Full GC回收常量池行为
        List<String> list = Lists.newArrayList();
        int i = 0;
        while (true) {
            list.add(String.valueOf(i++).intern());
        }
    }
    /**
     * 运行时常量溢出-问题思考
     * String.intern()是一个Native方法,
     * 作用是:如果字符串常量池中已经包含一个等于此String对象的字符串,
     * 则返回代表池中这个字符串的String对象,否则,将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。
     */
    public static void runtimeConstantPoolOOM2() {
        String str1 = new StringBuilder("土豆丝").append("不加辣").toString();
        String str11 = "土豆丝不加辣";
        //JDK 1.6 false JDK 1.7 true JDK 1.8 false
        System.out.println("========str1======" + (str1.intern() == str1));
        // JDK 1.8 true
        System.out.println("========str11======" + (str1.intern().equals(str11)));
        String str2 = new StringBuilder("ja").append("va").toString();
        String str22 = str2.intern();
        //JDK 1.6 false JDK 1.7 true JDK 1.8 false
        System.out.println("========str2======" + (str2 == str22));
    }
    /**
     * 方法区溢出
     * <p>
     * MetaSpace 溢出
     * 方法区的内存溢出 中, JDK8 没有了永久代的概念
     * 在JDK8中,使用了MetaSpace的区域来存放Class的相关信息,
     * 当 MetaSpace 内存空间不足时, 会抛出 java.lang.OutOfMemoryError: Metaspace异常.
     * $ -XX:MaxMetaspaceSize=5M
     * CGLIB直接操作字节码运行时,生成大量的动态类
     */
    public static void jdk8MethodAreaOOM() {
        while (true) {
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(JvmTest.class);
            enhancer.setUseCache(false);
            enhancer.setCallback(new MethodInterceptor() {
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    return methodProxy.invokeSuper(o, objects);
                }
            });
            enhancer.create();
        }
    }
    public static void main(String[] args) throws Throwable {
//        模拟OutOfMemoryError 堆溢出错误
//        JvmTest.outOfMemoryError();
//        JvmTest.heapOverFlow();
        //栈溢出
        JvmTest jvmTest = new JvmTest();
        try {
            jvmTest.stackOverflowError();
        } catch (Throwable e) {
            System.out.println("========Stack length:" + jvmTest.STACK_COUNT);
            throw e;
        }
//        运行时常量池导致内存溢出
//        JvmTest.runtimeConstantPoolOOM1();
//        JvmTest.runtimeConstantPoolOOM2();
        //jvm 8 永久代去掉使用 MetaSpace
//        JvmTest.jdk8MethodAreaOOM();
    }
}

二、调试上面代码最好在IDEA或者Eclipse中设置如下参数,会有更好的效果。

-Xms5m -Xmx5m -XX:MetaspaceSize=5m -XX:MaxMetaspaceSize=5M -Xss256k -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintHeapAtGC -XX:+PrintClassHistogram -XX:+HeapDumpOnOutOfMemoryError
jvm.png

本文共计 8613 字,感谢您的耐心浏览与评论。

声明:土豆丝不辣|版权所有,违者必究|如未注明,均为原创|转载请注明原文链接说明出处

0条回应:“常见JVM错误代码示例”