导读:当 JVM 内存严重不足时,就会抛出 java.lang.OutOfMemoryError 错误。本文总结了常见的 OOM 缘由及其解决方法,以下图所示。若有遗漏或错误,欢迎补充指正。html
当堆内存(Heap Space)没有足够空间存放新建立的对象时,就会抛出 java.lang.OutOfMemoryError:Javaheap space错误(根据实际生产经验,能够对程序日志中的 OutOfMemoryError 配置关键字告警,一经发现,当即处理)。java
Javaheap space错误产生的常见缘由能够分为如下几类:git
针对大部分状况,一般只须要经过 -Xmx参数调高 JVM 堆内存空间便可。若是仍然没有解决,能够参考如下状况作进一步处理:github
若是是超大对象,能够检查其合理性,好比是否一次性查询了数据库所有结果,而没有作结果数限制。数据库
若是是业务峰值压力,能够考虑添加机器资源,或者作限流降级。数组
若是是内存泄漏,须要找到持有的对象,修改代码设计,好比关闭没有释放的链接。缓存
当 Java 进程花费 98% 以上的时间执行 GC,但只恢复了不到 2% 的内存,且该动做连续重复了 5 次,就会抛出 java.lang.OutOfMemoryError:GC overhead limit exceeded错误。简单地说,就是应用程序已经基本耗尽了全部可用内存, GC 也没法回收。服务器
此类问题的缘由与解决方案跟 Javaheap space很是相似,能够参考上文。markdown
该错误表示永久代(Permanent Generation)已用满,一般是由于加载的 class 数目太多或体积太大。数据结构
永久代存储对象主要包括如下几类:
PermGen 的使用量与加载到内存的 class 的数量/大小正相关。
根据 Permgen space 报错的时机,能够采用不一样的解决方案,以下所示:
若是上述方法没法解决,能够经过 jmap 命令 dump 内存对象 jmap-dump:format=b,file=dump.hprof,而后利用 Eclipse MAT www.eclipse.org/mat功能逐一分析开销最大的 classloader 和重复 class。
JDK 1.8 使用 Metaspace 替换了永久代(Permanent Generation),该错误表示 Metaspace 已被用满,一般是由于加载的 class 数目太多或体积太大。
此类问题的缘由与解决方法跟 Permgenspace很是相似,能够参考上文。须要特别注意的是调整 Metaspace 空间大小的启动参数为 -XX:MaxMetaspaceSize。
每一个 Java 线程都须要占用必定的内存空间,当 JVM 向底层操做系统请求建立一个新的 native 线程时,若是没有足够的资源分配就会报此类错误。
JVM 向 OS 请求建立 native 线程失败,就会抛出 Unableto createnewnativethread,常见的缘由包括如下几类:
该问题发生的常见过程主要包括如下几步:
ulimit -a .... 省略部份内容 ..... max user processes (-u) 16384
该错误表示全部可用的虚拟内存已被耗尽。虚拟内存(Virtual Memory)由物理内存(Physical Memory)和交换空间(Swap Space)两部分组成。当运行时程序请求的虚拟内存溢出时就会报 Outof swap space?错误。
该错误出现的常见缘由包括如下几类:
根据错误缘由能够采起以下解决方案:
升级地址空间为 64 bit;
使用 Arthas 检查是否为 Inflater/Deflater 解压缩问题,若是是,则显式调用 end 方法。
Direct ByteBuffer 问题能够经过启动参数 -XX:MaxDirectMemorySize调低阈值。
升级服务器配置/隔离部署,避免争用。
有一种内核做业(Kernel Job)名为 Out of Memory Killer,它会在可用内存极低的状况下“杀死”(kill)某些进程。OOM Killer 会对全部进程进行打分,而后将评分较低的进程“杀死”,具体的评分规则能够参考 Surviving the Linux OOM Killer。
不一样于其余的 OOM 错误, Killprocessorsacrifice child错误不是由 JVM 层面触发的,而是由操做系统层面触发的。
默认状况下,Linux 内核容许进程申请的内存总量大于系统可用内存,经过这种“错峰复用”的方式能够更有效的利用系统资源。
然而,这种方式也会无可避免地带来必定的“超卖”风险。例如某些进程持续占用系统内存,而后致使其余进程没有可用内存。此时,系统将自动激活 OOM Killer,寻找评分低的进程,并将其“杀死”,释放内存资源。
升级服务器配置/隔离部署,避免争用。
OOM Killer 调优。
JVM 限制了数组的最大长度,该错误表示程序请求建立的数组超过最大长度限制。
JVM 在为数组分配内存前,会检查要分配的数据结构在系统中是否可寻址,一般为 Integer.MAX_VALUE-2。
此类问题比较罕见,一般须要检查代码,确认业务是否须要建立如此大的数组,是否能够拆分为多个块,分批执行。
Java 容许应用程序经过 Direct ByteBuffer 直接访问堆外内存,许多高性能程序经过 Direct ByteBuffer 结合内存映射文件(Memory Mapped File)实现高速 IO。
Direct ByteBuffer 的默认大小为 64 MB,一旦使用超出限制,就会抛出 Directbuffer memory错误。
做者 | 智哥
更多技术干货敬请关注码农架构技术号:码农架构 - 掘金
本文为**码农架构**原创内容,未经容许不得转载。