java outofmemory异常_OutOfMemoryError异常的几种原因

在Java虚拟机规范中,除了程序计数器外,虚拟机内存的其他几个运行时区域都可能会发生OutOfMemoryError异常。

在IDEA中添加JVM参数如下:

68cb1642cd8adf73817b490e43e10eae.png         

17be124b8924a3f12950e2b5f8067dc8.png

一、Java堆溢出

Java堆主要是用来存储对象,系统中不断的创建对象,并且在GC Roots到对象之间有可达路径,使垃圾回收机制不会回收这些对象,那么在对象数量达到最大堆的容量限制后就会产生内存溢出异常。代码如下:

/**

* JVM参数:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=E:\test\heapdump.hprof

* -Xms:堆的最小内存

* -Xmx:堆的最大内存

* -XX:+HeapDumpOnOutOfMemoryError :出现内存溢出时Dump出当前内存堆转储快照

* -XX:HeapDumpPath= :快照的存放路径

*/

public class HeapOOM {

static class OOMObject{}

public static void main(String[] args) {

List list = new ArrayList();

//不停的创建OOMObject

while (true){

list.add(new OOMObject());

}

}

}

运行结果:

bd896f9bf688085a84779d0841a299c5.png

堆内存溢出在实际应用中还是很常见的,出现堆内存溢出时,异常信息“java.lang.OutOfMemoryError”后会进一步提示 “Java heap space”。出现这个异常可以通过分析工具分析,确认时内存泄漏还是内存溢出。如果是泄露的话,继续使用工具分析具体泄露位置;不存在泄露,看看是不是可以加大堆内存容量。

二、虚拟机栈和本地方法栈溢出

HotSpot虚拟机不区分虚拟机栈和本地方法栈,所以设置本地方法栈的参数-Xoss并没有效果;栈的容量只由-Xss参数设定。关于栈,Java虚拟机规范描述了两种异常:①如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。②如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。我们这里仅测试StackOverflowError异常如下:

/**

* JVM参数:-Xss128k

* 默认栈容量深度为:19029

* 修改栈容量为128k深度为:1001

* 通过减小栈的容量,可见栈的深度也变小。

*/

public class JavaVMStackSOF {

private int stackLength = 1;

public void stackLeak() {

stackLength++;

stackLeak();

}

public static void main(String[] args) throws Throwable {

JavaVMStackSOF oom = new JavaVMStackSOF();

try{

oom.stackLeak();

}catch (Throwable e){

System.out.println("Stack Length :" + oom.stackLength);

throw e;

}

}

}

运行结果:(不同机器测试结果数量可能不同)

默认情况下:

c3a43d4482faacf6b04efa4bac7865e7.png                                  -Xss128k:  

cc83014c49103ff481bb05763490f82a.png

虚拟机使用默认参数,栈深度在大多数情况下,完全够用了(包括递归)。

三、方法区(元数据区)溢出

在JDK7之前方法区可以通过PermSize永久代大小和MaxPermSize最大永久代大小设置,如:-XX:PermSize=10m -XX:MaxPermSize=10m 。但是在JDK8中已经完全移除了永久代,PermSize和MaxPermSize参数也一并移除了。在移除了Perm区域之后,JDK8中使用MetaSpace来替代,这些空间都直接在堆上来进行分配。  在JDK8中,类的元数据存放在native堆中,这个空间被叫做:元数据区。JDK8中给元数据区添加了一些新的参数:

①-XX:MetaspaceSize= :是分配给类元数据区(以字节计)的初始大小(初始高水位),超过会导致垃圾收集器卸载类。这个数量是一个估计值。当第一次到达高水位的时候,下一个高水位是由垃圾收集器来管理的。

②-XX:MaxMetaspaceSize= :是分配给类元数据区的最大值(以字节计)。这个参数可以用来限制分配给类元数据区的大小。这个值也是个估计值。默认无上限。

③-XX:MinMetaspaceFreeRatio=:是一次GC以后,为了避免增加元数据区(高水位)的大小,空闲的类元数据区的容量的最小比例,不够就会导致垃圾回收。

④  -XX:MaxMetaspaceFreeRatio=:是一次GC以后,为了避免减少元数据区(高水位)的大小,空闲的类元数据区的容量的最大比例,超过就会导致垃圾回收。

借助CGLib使元数据区出现内存溢出测试如下:

/**

* JVM参数:-XX:MetaspaceSize=5M -XX:MaxMetaspaceSize=5M (JDK8)

* -XX:PermSize=10m -XX:MaxPermSize=10m (JDK7)

* 需要引入cglib依赖

*/

public class JavaMethodAreaOOM {

public static void main(final String[] args) {

while (true){

Enhancer enhancer = new Enhancer();

enhancer.setSuperclass(OOMObject.class);

enhancer.setUseCache(false);

enhancer.setCallback(new MethodInterceptor() {

public Object intercept(Object obj, Method method, Object[] objects, MethodProxy proxy) throws Throwable {

return proxy.invokeSuper(obj,args);

}

});

enhancer.create();

}

}

static class OOMObject{}

}

运行结果:

06cf2a2afee7158b922bbfc7188da2e2.png

在很多主流框架中都是用到了CGLib,如Spring、Hibernate,需要增强的类越多,就需要越大的元数据区来保证动态生成的Class可以加载入内存。

四、本机直接内存溢出

本机直接内存溢出(程序中直接或简介使用了NIO会导致),不像上面几种OutOfMemoryError会告诉我们溢出的位置,如下:

/**

* JVM参数:-Xmx20m -XX:MaxDirectMemorySize=10m

*/

public class DircetMemoryOOM {

private static final int _1MB = 1024*1024;

public static void main(String[] args) throws IllegalAccessException {

Field unsafeField = Unsafe.class.getDeclaredFields()[0];

unsafeField.setAccessible(true);

Unsafe unsafe = (Unsafe) unsafeField.get(null);

while (true){

unsafe.allocateMemory(_1MB);

}

}

}

运行结果:

9d927470812d402248e13904eeeb806d.png

源代码:https://gitee.com/itcaofanqi/CaoFanqiStudyRepository/tree/master/stujvm

参考:周志明《深入理解Java虚拟机》

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值