来 给朕手写一个OOM异常的栗子

2.4 实战 OutOfMemoryError 异常

面试官:项目中你有没有遇到过Java虚拟机方面的问题,做过虚拟机调优嘛,来,给朕手写一个堆内存溢出的Demo

注:IDEA内存映像分析工具: https://blog.csdn.net/qq_19674905/article/details/80824858

Jprofile exe:https://www.ej-technologies.com/download/jprofiler/version_92

2.4.1 Java堆溢出

import java.util.ArrayList;

/**
 * @Description HeapOOM
 * @Author Zerah
 * @Date 2019/12/20 13:04
 *  VM args: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
 */
public class HeapOOM {
    static class OOMObject{

    }

    public static void main(String[] args) {
        ArrayList<OOMObject> list = new ArrayList<>();
        while (true){
            list.add(new OOMObject());
        }
    }
    /** 运行结果
        java.lang.OutOfMemoryError: Java heap space
        Dumping heap to java_pid7472.hprof ...
        Heap dump file created [28238887 bytes in 0.175 secs]
        Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    **/
}

2.4.2 虚拟机栈和本地方法栈溢出

/**
 * @Description JavaVMStackSOF 虚拟机栈和本地方法栈溢出OOM测试
 * @Author Zerah
 * @Date 2019/12/20 13:35
 * VM args: -Xss128k
 */
public class JavaVMStackSOF {
    private int stackLength =1;
    public void stackLeak(){
        stackLength ++;
        stackLeak();
    }

    public static void main(String[] args) throws Throwable{
        JavaVMStackSOF stackSOF = new JavaVMStackSOF();
        try {
            stackSOF.stackLeak();
        } catch (Throwable e) {
            System.out.println("stack length:"+ stackSOF.stackLength);
            throw e;
        }
    }
    /** 运行结果:
     * stack length:1611
     * Exception in thread "main" java.lang.StackOverflowError
     * 	at com.zerah.concurrent.jvm.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:13)
     * 	at com.zerah.concurrent.jvm.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:13)
     * 	at com.zerah.concurrent.jvm.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:13)
     * 	省略。。。。。。
     */
}

/**
 * @Description JavaVMStackOOM 创建线程导致内存溢出异常, 别跑了,会把机子搞死机,别问我是怎么知道的,非要跑把其他软件能保存得保存下
 * @Author Zerah
 * @Date 2019/12/23 14:13
 * VM args: -Xss2M
 */
public class JavaVMStackOOM {
    private void dontStop(){
        while (true){

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

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

}

2.4.3 方法区和运行时常量池溢出

import java.util.ArrayList;

/**
 * @Description RuntimeConstantPoolOOM 运行时常量池导致的内存溢出异常      JDK1.6及之前版本可测试,1.6之前常量池在永久代中分配
 * String.intern() 是一个Native方法: 如果字符串常量池中已经包含一个等于此String对象得字符串,则返回常量池中代表这个字符串得【String对象】,
 *  否则,将此String对象包含的字符串添加到常量池中,并且返回此【String对象的引用】
 *
 *  如果使用JDK1.7 + 测试,如果不限制堆内存大小,while循环将一直进行下去,JDK1.7字符串常量池由永久代转移到堆中,JDK1.8之后移除永久代由元空间替代
 *  关于元空间的测试可以看:https://blog.csdn.net/qq_16681169/article/details/70471010
 * @Author Zerah
 * @Date 2019/12/23 14:25
 *
 * VM args: -XX:PermSize=10M -XX:MaxPermSize=10M
 * 如果限制对内存大小:-XX:PermSize=10M -XX:MaxPermSize=10M -Xmx15M
 */
public class RuntimeConstantPoolOOM {
    public static void main(String[] args) {
        // 使用List保持着常量池的引用,避免Full GC回收常量池
        ArrayList<String> list = new ArrayList<>();
        // 10MB的PermSize在Integer 范围内足够产生OOM了
        int i= 0;
        while (true){
            list.add(String.valueOf(i++).intern());
        }
    }
}

异常输出


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:265)
	at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:239)
	at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:231)
	at java.util.ArrayList.add(ArrayList.java:462)
	at com.zerah.concurrent.jvm.RuntimeConstantPoolOOM.main(RuntimeConstantPoolOOM.java:23)
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=10M; support was removed in 8.0
Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=10M; support was removed in 8.0
import java.lang.reflect.Method;

/**
 * @Description JavaMethodAreaOOM 借助CGLib 使方法区出现内存溢出异常 JDK1.6
 * @Author Zerah
 * @Date 2019/12/23 15:04
 * VM args: -XX:PermSize=10M -XX:MaxPermSize=10M
 */
public class JavaMethodAreaOOM {
    public static void main(String[] args) {
        while (true){
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(OOMObject.class);
            enhancer.setUseCache(false);
            enhancer.setCallback(new MethodInterceptor() {
                @Override
                public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                    return proxy.invokeSuper(obj,args);
                }
            });
            enhancer.create();
        }
    }
    static class OOMObject{}

}

2.4.4 本机直接内存溢出

import sun.misc.Unsafe;

import java.lang.reflect.Field;

/**
 * @Description DirectMemorryOOM
 * @Author Zerah
 * @Date 2019/12/23 15:49
 * VM args: -Xmx20M -XX:MaxDirectMemorySize=10M  如果不指定,默认与Java堆最大值(-Xmx)一样
 */
public class DirectMemoryOOM {
    private static final int _1MB = 1024*1024;

    public static void main(String[] args) throws Exception{
        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.zerah.concurrent.jvm.DirectMemoryOOM.main(DirectMemoryOOM.java:21)

注:本文栗子源自《深入理解Java虚拟机》

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值