OOM包路径:java.lang.object——>java.lang.Throwable——>java.lang.error—— >java.lang.VirtualMachineError——>java.lang.OutOfMemoryError
java.lang.StackOverflowError
栈溢出,深度的方法调用会导致栈溢出,线程请求的栈深度大于虚拟机所允许的深度
java.lang.OutOfMemoryError:Java heap space
堆内存溢出 对象多,新建大对象
java.lang.OutOfMemoryError:GC overhead limit exceeded
GC回收时间过长时会抛出OutOfMemroyError。
过长定义:超过98%的时间用来做GC并且回收了不到2%的堆内存,连续多次GC都只回收了不到2%的极端情况下才会抛出。
假如不抛出 GC overhead limit 错误的话,GC清理出来的这么点内存很快会再次集满,追使GC再次执行,这样就形成恶性循环;CPU使用率一直是100%,GC却没有任何成果
java.lang.OutOfMemoryError:Direct buffer memory
直接内存:不是运行时内存区域的一部分,但被频繁使用,1.4引入NIO概念,在新的nio类(基于通道(Channel)与缓冲区 (Buffer)的I/O方式),它可以使用Native函数库直接分配堆外内存,然后通过一个存储在Java堆里面的 DirectByteBuffer对象作为这块内存的引用进行操作。这样能在一些场景中显著提高性能,因为避免了在Java堆和Native堆中来回复制数据。不受堆的大小限制,但受物理机总内存(包括物理内存、SWAP分区或者分页文件)大小以及处理器寻址空间的限制。
异常:如果在配置虚拟机-Xmx等参数时,忽略了直接内存,使得各个内存区域总和大于物理内存限制,从而导致动态扩展时出现OOM
ByteBuffer.allocate(capability) 第一种方式是分配JVM堆内存,属于GC管辖范围,由于需要拷贝所以速度相对较慢
BvteBuffer.allocteDirect(capability) 第一种方式是分配OS本地内存,不属于GC管辖范围,由于不需要内存拷贝所以速度相对较快
但如果不断分配本地内存,堆内存很少使用,那么JVM就不需要执行GC,DirectByteBuffer对象就不会被回收,这时候堆内存充足,但本地内存可能已经使用光了,再次尝试分配本地内存就会出现OutOfMemoryError,那程序就直接崩溃了
java.lang.OutOfMemoryError:unable to create new native thread
高并发请求服务器时会出现
导致原因:
应用创建了太多的线程,超过系统承载极限,服务器并不允许一个应用程序创建这么多线程,linux系统默认允许单个进程可以创建的线程数是1024个,当应用创建超过这个数量,就会java.lang.OutOfMemoryError: unable to create new native thread
解决办法:
想办法降低应用程序创建的线程数量,分析应用是否真的需要创建这么多线程,如果不是,修改代码将线程数降到最低。若应用确实需要创建很多线程,远超过Linux系统的默认1024个线程的限制,可以通过修改Linux服务器配置,扩大Linux默认限制。
linux调整线程数
su z3
ulimit -u
vim /etc/security/limits.d/90-nproc.conf
java.lang.OutOfMemoryError:Metaspace
元空间溢出,不断生成类往元空间灌,类占据的空间总是会超过Metaspace指定的空间大小