优秀的编程知识分享平台

网站首页 > 技术文章 正文

OutOfMemoryError知多少(outofmemoryerror怎么解决)

nanyue 2024-10-12 05:45:20 技术文章 7 ℃

Java堆溢出

Java堆内存OOM是最常见的内存溢出。异常堆栈信息“java.lang.OutOfMemoryError” 会跟着进一步提示“Java heap space”。

一般通过内存映像分析工具对dump出来的堆转储快照进行分析,重点确认内存中的对象是否是必要的,也就是分析清楚到底是出现了内存泄漏还是内存溢出。

内存泄漏解决

通过工具查看泄漏对象到GC Roots的引用链,泄漏的对象是通过怎样的路径与GC Roots相关联并导致垃圾收集器无法自动回收它们的。

掌握了泄漏对象的类型信息,以及GC Roots引用链的信息,就可以定位泄漏代码的位置了。

内存溢出解决

如果不是泄漏,就说明这个对象确实需要活着。那就应当检查虚拟机的堆参数了(-Xmx 与-Xms),与及其物理内存对比看是否还可以调大,从代码上检查是否存在某些对象生命周期过长、持有状态时间过长的情况,尝试减少程序运行期的内存损耗。

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

在Java虚拟机规范中描述了两种异常:

  1. 线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常
  2. 虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常

其实本质上区分点在于程序是单线程和多线程。

单线程下很难模拟出OOM的情况,抛出的基本上都是StackOverflowError。

多线程下,基本上每个线程的栈分配的内存越大,反而越容易产生OOM(Java.lang.OutoOfMemoryError :unable to create new native Thread)的异常。

多线程应用下,出现StackOverflowError异常一般都有错误堆栈的信息,相对较为容易的找到问题原因。

虚拟机的默认参数,栈深度多数情况在2000以内完全没有问题,对于正常的方法调用,基本上都可以满足。

如果建立过多线程导致的内存溢出,只有两种办法来解决此类问题。

  1. 减少线程数
  2. 减少堆栈容量来换取更多的线程(-Xss j降低的每个线程栈大小的容量)。

永久代/元空间溢出

永久代是Hotspot虚拟机方法区的具体实现,存放了被虚拟机加载的类信息、常量、静态变量、JIT编译后的代码等。JDK8后,元空间替代了永久代,元空间使用的是本地内存。

出现内存溢出的异常信息为:java.lang.OutOfMemoryError: PermGem space

或者java.lang.OutOfMemroyError: Metaspace

一般解决思路如下:

1、通过参数设置永久代(-XX:MaxPermSize)或者元空间(-XX:MaxMetaspaceSize )的大小

2、检查代码中是否存在大量的反射操作

3、dump之后通过工具检查是否存在大量由于反射生成的代理类。

swap溢出

swap溢出(java.lang.OutOfMemoryError:Out of swap space)一般是操作系统导致的,swap分区大小分配不足或者其他进程消耗了所有的内存。

拆出去其他的进程,或者增加swap分区大小以及增加机器内存大小。

最近发表
标签列表