java模拟内存溢出并分析_模拟Java内存溢出

本文通过修改虚拟机启动参数,来剖析常见的java内存溢出异常(基于jdk1.8)。

修改虚拟机启动参数

这里我们使用的是IDEA集成开发环境,选择Run/Debug Configurations

sgs_tc_news.php?req=AL0fpBNMT_myUI8EAKzPkohRmX8YqXAwtKRkgDqI-bE=

然后选择Configuration,修改VM options配置,就可以修改虚拟机启动参数了,本文的示例代码doc注释部分将会给出需要设置的虚拟机参数。

sgs_tc_news.php?req=AL0fpBNMT_myUI8EAKzPkohRmX8YqXAwtKRkgDqI-bE=

Java堆溢出

这里简单解释一下代码,我们通过 -xms20m -Xmx20m 两个参数,限制了Java堆的大小为20MB,不可扩展,后两个参数控制了当出现了OutOfMemoryError时,会Dump出当前内存的 堆转储快照 ,并保存到指定位置中。

接下来我们可以使用jdk自带的VisualVM来打开快照文件。

命令行输入 jvisualvm ,点击左上角的 装入 ,选中我们dump出来的堆快照文件。

sgs_tc_news.php?req=AL0fpBNMT_myUI8EAKzPkohRmX8YqXAwtKRkgDqI-bE=

经过重新加载的堆内存记录如下:

sgs_tc_news.php?req=AL0fpBNMT_myUI8EAKzPkohRmX8YqXAwtKRkgDqI-bE=

这里可以很直观的看出,OutOfMemoryError产生的原因,是HeapOOM这个对象导致的。

解决问题的思路是:首先我们要排除 内存泄露 ,即我们不需要的对象没有被回收掉。我们要找到 泄漏的对象是如何与GC Root进行关联的? 从而准确定位出泄漏代码的位置,然后进行修改。

如果不是内存泄漏,即堆中的对象必须存活,这个时候,我们可以通过调节虚拟机的堆参数(-Xms -Xmx),适当调大堆内存。但是在此之前,我们一定要检查一下 代码是否存在优化的空间

,如:是否存在某些对象的生命周期过长?是否可以使用享元模式减少对象数量?等等

虚拟机栈溢出

StackOverflowError属于比较好排查的一种错误,有错误栈可以阅读,大部分出现这种错误,都是递归程序书写的问题,没有弄清楚什么时候需要return;结束递归。

sgs_tc_news.php?req=AL0fpBNMT_myUI8EAKzPkohRmX8YqXAwtKRkgDqI-bE=

这里有一个有趣的现象,操作系统给每个进程分配的内存是有限的,在多线程的场景下,如果每个线程分配的栈内存过大,就会导致OOM,这个时候可以适当减少每个线程的栈内存,来解决溢出问题(这可能不是最好的办法,只是因为这是一种比较不符合直觉的解决问题方式,所以这里单独说一下)。

方法区溢出

方法区用来存放Class相关的信息,比如类名、访问修饰符、常量池、字段描述等等。我们可以用运行时产生的大量的类填满方法区,这里我们使用了gclib来操作字节码,maven坐标如下:

代码:

如果你用的也是和我一样的jdk1.8,此时我们将没有办法得到OOM,因为在jdk1.8之后,PermGen已经被移除了,所以永久代的参数也被一同移除。方法区的 静态变量和常量池 并入堆中,而类的 元信息 放到元空间中,元空间是一块本地内存,所以它的最大可分配空间就是系统内存的最大可用空间。

我们可以将参数改为:VM Args: -XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=10m,再执行上述代码,发现即使在设置了元空间大小的情况下,仍然不会触发OOM,可见元空间可以有效解决方法区OOM问题(会触发元空间的垃圾回收策略)。

本机直接内存溢出

这种情况发生的比较少,直接内存的容量,我们可以通过-XX:MaxDirectMemorySize来指定,如果不指定,默认与堆的最大值一样。我们可以通过Unsafe提供的方法申请本地内存分配。

如果你是IDE集成开发环境,可能会因为内存不足结束执行程序。

来源:https://www.tuicool.com/articles/yiQnyq3

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值