java - 各类OOM分析

StackOverflowError

比较常见的问题,虚拟机栈中栈帧过多超出栈容量,常见发生在递归方法深度过深。

OutOfMemoryError

java heap space

java堆内存不足以放下新生成的对象实例,1.考虑是否程序中存在内存泄露导致大量不需要的实例仍然占用内存未被回收2.当前内存容量是否能够足够应用运行

GC overhead limit exceeded

GC回收时间过长时会抛出OutOfMemoryError,过长的定义是超过98%的时间用来做GC并且回收了不到2%的堆内存时会抛出此异常。当连续多次GC都只回收了不到2%的极端情况下才会抛出,假设不抛出异常,因为清理出的垃圾过少,内存很容易又达满,又将重新触发GC,形成恶性循环。

JVM给出这样一个参数:-XX:-UseGCOverheadLimit 禁用这个检查,其实这个参数解决不了内存问题,只是把错误的信息延后,替换成 java.lang.OutOfMemoryError: Java heap space。

Direct buffer memory

写NIO程序经常使用ByteBuffer来读取或者写入数据,这是一种基于通道与缓冲区的I/O方式,它可以使用Native函数库直接分配堆外内存,然后通过一个存储在java堆里面的DirectByteBuffer对象作为这块内存的引用进行操作。

这样能在一些场景中显著提高性能,因为避免了在Java堆和Native内存来回复制数据。

ByteBuffer.allocateDirect(capability) 通过分配本地内存,不属于GC管辖,所有对于这块的内存也无法做到垃圾自动回收,需要手动显示进行垃圾内存释放,当在这块内存持续分配内存达到MaxDirectMemorySize上限时就会产生异常。

unable to create new native thread

应用创建了过多的线程,超过了操作系统规定单进程允许的最大线程数,linux系统默认允许单个进程可以创建的线程数是1024个。

Metaspace

java 8 及之后的版本适用Metaspace来替代永久代。

Metaspace(元空间)是方法区在HotSpot中的实现,它与持久代最大的区别在于:Metaspace并不在虚拟机内存中而是使用本地内存
也即在java8,classes metadata(the virtual machines internal presentation of java class) 被存储在叫做Metaspace的native memory

Metaspace主要存放了一下信息:

  1. 虚拟机加载的类信息
  2. 常量池
  3. 静态变量
  4. 即使编译后的代码

当元空间存放的大小超过规定的最大值时MaxMetaspaceSize则会抛出异常

猜你喜欢

转载自www.cnblogs.com/cjunn/p/12233134.html