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虚拟机》