Java虚拟机常见内存溢出错误汇总
一、引言
从事java开发的小伙伴在平时的开发工作中,应该会遇见各式各样的异常和错误,在实际工作中积累的异常或者错误越多,趟过的坑越多,就会使我们编码更加的健壮,就会本能地避开很多严重的坑。以下介绍几个Java虚拟机常见内存溢出错误。以此警示,避免生产血案。
二、模拟Java虚拟机常见内存溢出错误
1、内存溢出之栈溢出错误
packagecom.jayway.oom; /** *栈溢出错误 *虚拟机参数:-Xms10m-Xmx10m *抛出异常:Exceptioninthread"main"java.lang.StackOverflowError */ publicclassStackOverflowErrorDemo{ publicstaticvoidmain(String[]args){ stackOverflowError(); } privatestaticvoidstackOverflowError(){ stackOverflowError(); } }
2、内存溢出之堆溢出错误
packagecom.jayway.oom; importjava.util.Random; /** *堆溢出错误 *虚拟机参数:-Xmx10m-Xms10m *抛出异常:Exceptioninthread"main"java.lang.OutOfMemoryError:Javaheapspace */ publicclassJavaHeapSpaceErrorDemo{ publicstaticvoidmain(String[]args){ Stringtemp="java"; //不断地在堆中开辟空间,创建对象,撑爆堆内存 while(true){ temp+=temp+newRandom().nextInt(111111111)+newRandom().nextInt(222222222); temp.intern(); } } }
3、内存溢出之GC超过执行限制错误
packagecom.jayway.oom; importjava.util.ArrayList; importjava.util.List; /** *GC超过执行限制错误 *虚拟机参数:-Xms10m-Xmx10m-XX:+PrintGCDetails-XX:MaxDirectMemorySize=5m **抛出异常:Exceptioninthread"main"java.lang.OutOfMemoryError:GCoverheadlimitexceeded **导致原因:GC回收时间过长会抛出OutOfMemoryError,何为过长,即超过98%的cpu时间用来做GC垃圾回收 *但是回收效果甚微,仅仅只有2%的CPU时间用来用户程序的工作,这种状态是很糟糕的,程序在不断地GC *形成恶性循环,CPU的使用率一直是满负荷的,正经活却没有干,这种情况虚拟机只好抛出错误来终止程序的执行 * *不断地FullGC,事倍功微 *[FullGC(Ergonomics)[PSYoungGen:2047K->2047K(2560K)][ParOldGen:7167K->7161K(7168K)]9215K->9209K(9728K),[Metaspace:3529K->3529K(1056768K)],0.0291829secs][Times:user=0.08sys=0.02,real=0.03secs] */ publicclassGCOverheadErrorDemo{ publicstaticvoidmain(String[]args){ inti=0; Listlist=newArrayList<>(); try{ while(true){ list.add(String.valueOf(++i).intern()); } }catch(Throwablee){ System.out.println("*****************i:"+i); e.printStackTrace(); throwe; } } }
4、内存溢出之直接内存溢出错误
packagecom.jayway.oom; importjava.nio.ByteBuffer; /** *直接内存溢出错误 *抛出异常:Exceptioninthread"main"java.lang.OutOfMemoryError:Directbuffermemory **配置虚拟机参数:-Xms10m-Xmx10m-XX:+PrintGCDetails-XX:MaxDirectMemorySize=5m **导致原因:通常NIO程序经常使用ByteBuffer来读取或者写入数据,这是一种基于通道(Channel)与缓冲区(Buffer)的IO方式, *它可以使用Native函数库直接分配堆外内存,然后通过一个存储在java堆里面的DirectByteBuffer对象作为这块内存的引用, *这样能子一些场景中显著提高性能,因为避免了在Java堆和Native内存中来回复制数据。 * *ByteBuffer.allocate(capability):分配JVM堆内存,数据GC的管辖范围,由于需要拷贝所以速度相对较慢 * *ByteBuffer.allocate(capability):分配OS本地内存,不属于GC管辖范围,由于不需要内存拷贝,所以速度相对较快。 * *但是如果不断分配本地内存,堆内存很少使用,那么JVM就不需要执行GC,DirectByteBuffer对象就不会被回收,此时如果继续分配堆外内存, *可能堆外内存已经被耗光了无法继续分配,此时程序就会抛出OutOfMemoryError,直接崩溃。 * */ publicclassDirectBufferMemoryErrorDemo{ publicstaticvoidmain(String[]args){ //默认JVM配置的最大直接内存是总物理内存的四分之一 longmaxDirectMemory=sun.misc.VM.maxDirectMemory()/1024/1024; System.out.println("配置的maxDirectMemory:"+maxDirectMemory+"MB"); ByteBufferbyteBuffer=ByteBuffer.allocateDirect(6*1024*1024); } }
5、内存溢出之无法创建新的本地线程
packagecom.jayway.oom; /** *内存溢出之无法创建新的本地线程 *抛出异常:java.lang.OutOfMemoryError:unabletocreatenewnativethread **描述: *高并发请求服务器时,经常出现java.lang.OutOfMemoryError:unabletocreatenewnativethread *nativethread异常与对应的平台有关 * *导致原因: *1、应用程序创建了太多线程了,一个应用进程创建的线程数超过系统承载极限。 *2、操作系统并不允许你的应用进程创建这么多的线程,linux系统默认允许单个进程可以创建的线程数是1024个 * *解决方法: *1、想办法降低应用进程创建的线程数量, *2、如果应用程序确实需要这么多线程,超过了linux系统的默认1024个限制,可以通过修改linux服务器配置,提高这个阈值。 * */ publicclassUnableCreateNativeThreadErrorDemo{ publicstaticvoidmain(String[]args){ for(inti=0;true;i++){ System.out.println("***************i:"+i); //不断得创建新线程,直到超过操作系统允许应用进程创建线程的极限 newThread(()->{ try{ Thread.sleep(Integer.MAX_VALUE); }catch(InterruptedExceptione){ e.printStackTrace(); } }).start(); } } }
6、内存溢出之元空间溢出错误
packagecom.jayway.oom; importorg.springframework.cglib.proxy.Enhancer; importorg.springframework.cglib.proxy.MethodInterceptor; importorg.springframework.cglib.proxy.MethodProxy; importjava.lang.reflect.Method; /** *元空间溢出错误 *抛出异常:java.lang.OutOfMemoryError:Metaspace **设置虚拟机参数:-XX:MetaspaceSize=8m-XX:MaxMetaspaceSize=8m **描述:Java8及以后的版本使用Metaspace来替代了永久代。metaspace是方法区在HotSpot中的实现,它与持久代最大的区别在于 *Metaspace并不在虚拟机内存中而是在本地内存中。 * *元空间存储了以下信息: *1、虚拟机加载的类信息 *2、常量池 *3、静态变量 *4、即时编译后的代码 * */ publicclassMetaspaceErrorDemo{ staticclassOOMTest{ } publicstaticvoidmain(String[]args){ intcount=0; try{ //cglib不断创建类,模拟Metaspace空间溢出,我们不断生成类往元空间中灌,超过元空间大小后就会抛出元空间移除的错误 while(true){ count++; Enhancerenhancer=newEnhancer(); enhancer.setSuperclass(OOMTest.class); enhancer.setUseCache(false); enhancer.setCallback(newMethodInterceptor(){ @Override publicObjectintercept(Objecto,Methodmethod,Object[]objects,MethodProxymethodProxy)throwsThrowable{ returnmethodProxy.invokeSuper(o,args); } }); enhancer.create(); } }catch(Throwablee){ System.out.println("************多少次后发生了异常:"+count); e.printStackTrace(); } } }
以上就是Java虚拟机常见内存溢出错误汇总的详细内容,更多关于Java虚拟机内存溢出的资料请关注毛票票其它相关文章!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。