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

2022-09-24 11:17:55

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
 */publicclassHeapOOM{staticclassOOMObject{}publicstaticvoidmain(String[] args){
        ArrayList<OOMObject> list=newArrayList<>();while(true){
            list.add(newOOMObject());}}/** 运行结果
        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
 */publicclassJavaVMStackSOF{privateint stackLength=1;publicvoidstackLeak(){
        stackLength++;stackLeak();}publicstaticvoidmain(String[] args)throws Throwable{
        JavaVMStackSOF stackSOF=newJavaVMStackSOF();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
 */publicclassJavaVMStackOOM{privatevoiddontStop(){while(true){}}publicvoidstackLeakByThread(){while(true){
            Thread thread=newThread(newRunnable(){@Overridepublicvoidrun(){dontStop();}});
            thread.start();}}publicstaticvoidmain(String[] args){
        JavaVMStackOOM oom=newJavaVMStackOOM();
        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
 */publicclassRuntimeConstantPoolOOM{publicstaticvoidmain(String[] args){// 使用List保持着常量池的引用,避免Full GC回收常量池
        ArrayList<String> list=newArrayList<>();// 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
 */publicclassJavaMethodAreaOOM{publicstaticvoidmain(String[] args){while(true){
            Enhancer enhancer=newEnhancer();
            enhancer.setSuperclass(OOMObject.class);
            enhancer.setUseCache(false);
            enhancer.setCallback(newMethodInterceptor(){@Overridepublic Objectintercept(Object obj, Method method, Object[] args, MethodProxy proxy)throws Throwable{return proxy.invokeSuper(obj,args);}});
            enhancer.create();}}staticclassOOMObject{}}

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)一样
 */publicclassDirectMemoryOOM{privatestaticfinalint _1MB=1024*1024;publicstaticvoidmain(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虚拟机》

  • 作者:ZerahMu
  • 原文链接:https://blog.csdn.net/NathanniuBee/article/details/103667408
    更新时间:2022-09-24 11:17:55