《深入理解Java虚拟机》之实战OutOfMemoryError

Java堆溢出

/**
 * -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDetails
 */
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_pid3336.hprof ...
Heap dump file created [28493647 bytes in 0.078 secs]
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.java.study.jvm.error.HeapOOM.main(HeapOOM.java:14)
Heap
 PSYoungGen      total 6144K, used 3120K [0x00000000ff980000, 0x0000000100000000, 0x0000000100000000)
  eden space 5632K, 55% used [0x00000000ff980000,0x00000000ffc8c118,0x00000000fff00000)
  from space 512K, 0% used [0x00000000fff00000,0x00000000fff00000,0x00000000fff80000)
  to   space 512K, 0% used [0x00000000fff80000,0x00000000fff80000,0x0000000100000000)
 ParOldGen       total 13824K, used 13786K [0x00000000fec00000, 0x00000000ff980000, 0x00000000ff980000)
  object space 13824K, 99% used [0x00000000fec00000,0x00000000ff976848,0x00000000ff980000)
 Metaspace       used 3333K, capacity 4500K, committed 4864K, reserved 1056768K
  class space    used 360K, capacity 388K, committed 512K, reserved 1048576K

虚拟机栈溢出

/**
 * -Xss128k
 */
public class StackSof {
    private int stackLength = 1;

    public void stackLeak() {
        stackLength++;
        stackLeak();
    }

    public static void main(String[] args) {
        StackSof stackSof = new StackSof();
        try{
            stackSof.stackLeak();
        } catch (Throwable e){
            System.out.println("stack length:" + stackSof.stackLength);
            throw e;
        }
    }
}

异常:

stack length:999
Exception in thread "main" java.lang.StackOverflowError
	at com.java.study.jvm.error.StackSof.stackLeak(StackSof.java:10)
	at com.java.study.jvm.error.StackSof.stackLeak(StackSof.java:11)

局部变量表太大导致栈溢出:

public class StackSof2 {
    private static int stackLength = 0;

    private static void test() {
        long unused1,unused2,unused3,unused4,unused5,
                unused6,unused7,unused8,unused9,unused10,
                unused11,unused12,unused13,unused14,unused15,
                unused16,unused17,unused18,unused19,unused20,
                unused21,unused22,unused23,unused24,unused25,
                unused26,unused27,unused28,unused29,unused30,
                unused31,unused32,unused33,unused34,unused35,
                unused36,unused37,unused38,unused39,unused40,
                unused41,unused42,unused43,unused44,unused45,
                unused46,unused47,unused48,unused49,unused50,
                unused51,unused52,unused53,unused54,unused55,
                unused56,unused57,unused58,unused59,unused60,
                unused61,unused62,unused63,unused64,unused65,
                unused66,unused67,unused68,unused69,unused70,
                unused71,unused72,unused73,unused74,unused75,
                unused76,unused77,unused78,unused79,unused80,
                unused81,unused82,unused83,unused84,unused85,
                unused86,unused87,unused88,unused89,unused90,
                unused91,unused92,unused93,unused94,unused95,
                unused96,unused97,unused98,unused99,unused100;

        stackLength++;
        test();
        unused1=unused2=unused3=unused4=unused5=
                unused6=unused7=unused8=unused9=unused10=
                unused11=unused12=unused13=unused14=unused15=
                unused16=unused17=unused18=unused19=unused20=
                unused21=unused22=unused23=unused24=unused25=
                unused26=unused27=unused28=unused29=unused30=
                unused31=unused32=unused33=unused34=unused35=
                unused36=unused37=unused38=unused39=unused40=
                unused41=unused42=unused43=unused44=unused45=
                unused46=unused47=unused48=unused49=unused50=
                unused51=unused52=unused53=unused54=unused55=
                unused56=unused57=unused58=unused59=unused60=
                unused61=unused62=unused63=unused64=unused65=
                unused66=unused67=unused68=unused69=unused70=
                unused71=unused72=unused73=unused74=unused75=
                unused76=unused77=unused78=unused79=unused80=
                unused81=unused82=unused83=unused84=unused85=
                unused86=unused87=unused88=unused89=unused90=
                unused91=unused92=unused93=unused94=unused95=
                unused96=unused97=unused98=unused99=unused100 =1L;


    }

    public static void main(String[] args) {
        try{
            test();
        } catch (Throwable e){
            System.out.println("stack length:" + stackLength);
            throw e;
        }
    }
}

异常:

stack length:9094
Exception in thread "main" java.lang.StackOverflowError
	at com.java.study.jvm.error.StackSof2.test(StackSof2.java:32)

第三个异常

public class StackOom {
    private void dontStop() {
        while(true){}
    }

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

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

这个测试卡死......

运行时常量池导致内存溢出

也可证明运行时常量池在JDK1.8中放在堆内存中进行分配

/**
* -Xms2m -Xmx2m -XX:+PrintGCDetails
*/
public class RunTimeConstantPoolOom {
    public static void main(String[] args) {
        Set<String> set = new HashSet<String>();
        short i = 0;
        while(true) {
            set.add(String.valueOf(i++).intern());
        }
    }
}

运行结果

[GC (Allocation Failure) [PSYoungGen: 996K->488K(1024K)] 1196K->768K(1536K), 0.0015586 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC (Allocation Failure) --[PSYoungGen: 1000K->1000K(1024K)] 1280K->1504K(1536K), 0.0025075 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
......
[Full GC (Allocation Failure) [PSYoungGen: 512K->512K(1024K)] [ParOldGen: 512K->512K(512K)] 1024K->1024K(1536K), [Metaspace: 3381K->3381K(1056768K)], 0.0046853 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
[Full GC (Ergonomics) [PSYoungGen: 512K->0K(1024K)] [ParOldGen: 512K->488K(512K)] 1024K->488K(1536K), [Metaspace: 3382K->3382K(1056768K)], 0.0045192 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
	at java.util.HashMap.newNode(HashMap.java:1747)
	at java.util.HashMap.putVal(HashMap.java:642)
	at java.util.HashMap.put(HashMap.java:612)
	at java.util.HashSet.add(HashSet.java:220)
	at com.java.study.jvm.RunTimeConstantPoolOom.main(RunTimeConstantPoolOom.java:11)
Heap
 PSYoungGen      total 1024K, used 33K [0x00000007bfe80000, 0x00000007c0000000, 0x00000007c0000000)
  eden space 512K, 6% used [0x00000007bfe80000,0x00000007bfe88718,0x00000007bff00000)
  from space 512K, 0% used [0x00000007bff80000,0x00000007bff80000,0x00000007c0000000)
  to   space 512K, 43% used [0x00000007bff00000,0x00000007bff37230,0x00000007bff80000)
 ParOldGen       total 512K, used 488K [0x00000007bfe00000, 0x00000007bfe80000, 0x00000007bfe80000)
  object space 512K, 95% used [0x00000007bfe00000,0x00000007bfe7a000,0x00000007bfe80000)
 Metaspace       used 3414K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 375K, capacity 388K, committed 512K, reserved 1048576K

方法区内存溢出

/**
 * -Xms5m -Xmx5m -XX:+PrintGCDetails
 */
public class MethodAreaOom {
    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 o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    return methodProxy.invokeSuper(o, args);
                }
            });
            enhancer.create();
        }
    }
}

class OOMObject{}

当堆内存设置很小时,异常是java.lang.OutOfMemoryError: GC overhead limit exceeded

这个错误是由于JVM花费太长时间执行GC且只能回收很少的堆内存时抛出的。根据Oracle官方文档,默认情况下,如果Java进程花费98%以上的时间执行GC,并且每次只有不到2%的堆被恢复,则JVM抛出此错误。

[Full GC (Ergonomics) [PSYoungGen: 1024K->1019K(1536K)] [ParOldGen: 4023K->4016K(4096K)] 5047K->5035K(5632K), [Metaspace: 25649K->25649K(1073152K)], 0.0124783 secs] [Times: user=0.04 sys=0.00, real=0.02 secs] 
[Full GC (Ergonomics) [PSYoungGen: 1024K->977K(1536K)] [ParOldGen: 4016K->4003K(4096K)] 5040K->4980K(5632K), [Metaspace: 25649K->25649K(1073152K)], 0.0121685 secs] [Times: user=0.03 sys=0.00, real=0.01 secs] 
Exception in thread "main" [Full GC (Ergonomics) [PSYoungGen: 1024K->984K(1536K)] [ParOldGen: 4003K->4001K(4096K)] 5027K->4985K(5632K), [Metaspace: 25660K->25656K(1073152K)], 0.0131160 secs] [Times: user=0.03 sys=0.00, real=0.01 secs] 
java.lang.OutOfMemoryError: GC overhead limit exceeded
	at org.springframework.asm.ByteVector.<init>(ByteVector.java:55)
	at org.springframework.asm.ClassWriter.toByteArray(ClassWriter.java:604)
	at org.springframework.cglib.core.DebuggingClassWriter$1.run(DebuggingClassWriter.java:78)
[Full GC (Ergonomics) [PSYoungGen: 1024K->975K(1536K)] [ParOldGen: 4001K->4000K(4096K)] 5025K->4976K(5632K), [Metaspace: 25667K->25660K(1073152K)], 0.0165955 secs] [Times: user=0.04 sys=0.00, real=0.02 secs] 
	at java.security.AccessController.doPrivileged(Native Method)
	at org.springframework.cglib.core.DebuggingClassWriter.toByteArray(DebuggingClassWriter.java:73)
[Full GC (Ergonomics) [PSYoungGen: 1024K->975K(1536K)] [ParOldGen: 4000K->4000K(4096K)] 5024K->4976K(5632K), [Metaspace: 25663K->25663K(1073152K)], 0.0190048 secs] [Times: user=0.04 sys=0.00, real=0.02 secs] 
	at org.springframework.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:26)
	at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:358)
	at org.springframework.cglib.proxy.Enhancer.generate(Enhancer.java:585)
	at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:131)
	at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:319)
	at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:572)
	at org.springframework.cglib.proxy.Enhancer.create(Enhancer.java:387)
	at com.java.study.jvm.MethodAreaOom.main(MethodAreaOom.java:21)

添加-XX:MetaspaceSize=50m -XX:MaxMetaspaceSize=50m参数后:

[GC (Last ditch collection) [PSYoungGen: 0K->0K(5632K)] 9517K->9517K(19456K), 0.0020960 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 
[Full GC (Last ditch collection) [PSYoungGen: 0K->0K(5632K)] [ParOldGen: 9517K->9517K(13824K)] 9517K->9517K(19456K), [Metaspace: 50577K->50577K(1095680K)], 0.0263803 secs] [Times: user=0.06 sys=0.00, real=0.02 secs] 
Caused by: java.lang.OutOfMemoryError: Metaspace
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
	at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:535)

本机直接内存溢出

/**
 * -Xms20m -Xmx20m -XX:MaxDirectMemorySize=10M
 */
public class DirectMemoryOom {
    private static final int _1MB = 1024 * 1024;

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

异常

Process finished with exit code 137 (interrupted by signal 9: SIGKILL)
posted @ 2020-12-02 20:27  曹自标  阅读(108)  评论(0编辑  收藏  举报