当JVM内存严重不足时,就会抛出java.lang.OutOfMemoryError错误。本文总结了常见的OOM原因及其解决方法,如下图所示。如有遗漏或错误,欢迎补充指正。

1、Java heap space

当堆内存(Heap Space)没有足够空间存放新创建的对象时,就会抛出java.lang.OutOfMemoryError:Javaheap space错误(根据实际生产经验,可以对程序日志中的OutOfMemoryError配置关键字告警,一经发现,立即处理)。

原因分析

Javaheap space错误产生的常见原因可以分为以下几类:

1、请求创建一个超大对象,通常是一个大数组。

2、超出预期的访问量/数据量,通常是上游系统请求流量飙升,常见于各类促销/秒杀活动,可以结合业务流量指标排查是否有尖状峰值。

3、过度使用终结器(Finalizer),该对象没有立即被GC。

4、内存泄漏(Memory Leak),大量对象引用没有释放,JVM无法对其自动回收,常见于使用了File等资源没有回收。

2、GC overhead limit exceeded

当Java进程花费98%以上的时间执行GC,但只恢复了不到2%的内存,且该动作连续重复了5次,就会抛出java.lang.OutOfMemoryError:GC overhead limit exceeded错误。简单地说,就是应用程序已经基本耗尽了所有可用内存,GC也无法回收。

3、Permgen space

该错误表示永久代(Permanent Generation)已用满,通常是因为加载的class数目太多或体积太大。

原因分析

永久代存储对象主要包括以下几类:

1、加载/缓存到内存中的class定义,包括类的名称,字段,方法和字节码;

2、常量池;

3、对象数组/类型数组所关联的class;

4、JIT编译器优化后的class信息。

PermGen的使用量与加载到内存的class的数量/大小正相关。

4、Metaspace

JDK 1.8使用Metaspace替换了永久代(Permanent Generation),该错误表示Metaspace已被用满,通常是因为加载的class数目太多或体积太大。

需要特别注意的是调整Metaspace空间大小的启动参数为-XX:MaxMetaspaceSize。

5、Unable to create new native thread

每个Java线程都需要占用一定的内存空间,当JVM向底层操作系统请求创建一个新的native线程时,如果没有足够的资源分配就会报此类错误。

原因分析

JVM向OS请求创建native线程失败,就会抛出Unableto createnewnativethread,常见的原因包括以下几类:

1、线程数超过操作系统最大线程数ulimit限制;

2、线程数超过kernel.pid_max(只能重启);

3、native内存不足;

该问题发生的常见过程主要包括以下几步:

1、JVM内部的应用程序请求创建一个新的Java线程;

2、JVM native方法代理了该次请求,并向操作系统请求创建一个native线程;

3、操作系统尝试创建一个新的native线程;并为其分配内存;

4、如果操作系统的虚拟内存已耗尽,或是受到32位进程的地址空间限制,操作系统就会拒绝本次native内存分配;

5、JVM抛出java.lang.OutOfMemoryError:Unableto createnewnativethread错误。

6、Out of swap space?

该错误表示所有可用的虚拟内存已被耗尽。虚拟内存(Virtual Memory)由物理内存(Physical Memory)和交换空间(Swap Space)两部分组成。当运行时程序请求的虚拟内存溢出时就会报Outof swap space?错误。

原因分析

该错误出现的常见原因包括以下几类:

1、地址空间不足;

2、物理内存已耗光;

3、应用程序的本地内存泄漏(native leak),例如不断申请本地内存,却不释放。

4、执行jmap-histo:live命令,强制执行Full GC;如果几次执行后内存明显下降,则基本确认为Direct ByteBuffer问题。

7、Kill process or sacrifice child

有一种内核作业(Kernel Job)名为Out of Memory Killer,它会在可用内存极低的情况下“杀死”(kill)某些进程。OOM Killer会对所有进程进行打分,然后将评分较低的进程“杀死”,具体的评分规则可以参考Surviving the Linux OOM Killer。

不同于其他的OOM错误,Killprocessorsacrifice child错误不是由JVM层面触发的,而是由操作系统层面触发的。

原因分析

默认情况下,Linux内核允许进程申请的内存总量大于系统可用内存,通过这种“错峰复用”的方式可以更有效的利用系统资源。

然而,这种方式也会无可避免地带来一定的“超卖”风险。例如某些进程持续占用系统内存,然后导致其他进程没有可用内存。此时,系统将自动激活OOM Killer,寻找评分低的进程,并将其“杀死”,释放内存资源。

8、Requested array size exceeds VM limit

JVM限制了数组的最大长度,该错误表示程序请求创建的数组超过最大长度限制。

JVM在为数组分配内存前,会检查要分配的数据结构在系统中是否可寻址,通常为Integer.MAX_VALUE-2。

此类问题比较罕见,通常需要检查代码,确认业务是否需要创建如此大的数组,是否可以拆分为多个块,分批执行。

9、Direct buffer memory

Java允许应用程序通过Direct ByteBuffer直接访问堆外内存,许多高性能程序通过Direct ByteBuffer结合内存映射文件(Memory Mapped File)实现高速IO。

原因分析

Direct ByteBuffer的默认大小为64 MB,一旦使用超出限制,就会抛出Directbuffer memory错误。

Java开发中出现OOM的常见原因有哪些?相关推荐

  1. Java开发中更多常见的危险信号

    在< Java开发中的常见危险信号>一文中,我研究了一些不一定本身就是错误或不正确的做法,但它们可能表明存在更大的问题. 这些"红色标记"类似于"代码气味&q ...

  2. Java开发中的常见危险信号

    在开发,阅读,复审和维护成千上万行Java代码的几年中,我已经习惯于看到Java代码中的某些" 危险信号 ",这些信号通常(但可能并非总是)暗示着代码问题. 我不是在谈论总是错误的 ...

  3. Java开发中常见的危险信号(中)

    本文来源于我在InfoQ中文站原创的文章,原文地址是:http://www.infoq.com/cn/news/2013/12/common-red-flags-in-java-1 Dustin Ma ...

  4. Java开发中常见的危险信号(下)

    本文来源于我在InfoQ中文站原创的文章,原文地址是:http://www.infoq.com/cn/news/2013/12/common-red-flags-in-java-3 Dustin Ma ...

  5. Java开发中常见的危险信号

    Dustin Marx是一位专业软件开发者,从业已经有17年的时间,他拥有电子工程学士学位,还是一位MBA.Dustin维护着一个博客,专门介绍软件开发的各个主题.近日,他撰文谈到了Java开发中常见 ...

  6. 编写高质量代码:改善Java程序的151个建议 (第1章 Java开发中通用的方法和准则)

    第1章 Java开发中通用的方法和准则 The reasonable man adapts himself to the world;the unreasonable one persists in ...

  7. java路径Java开发中获得非Web项目的当前项目路径

    最近使用开发的过程中出现了一个小问题,顺便记录一下原因和方法--java路径 Java开发中指定路径搜索文件也是经常遇到的,比如遍历某个目录下的文件.须要取得项目的路径.调用调查主要有两种 1.利用S ...

  8. 嵌入式开发-浅谈嵌入式MCU开发中的三个常见误区

    浅谈嵌入式MCU开发中的三个常见误区 原创 2017-09-30 胡恩伟 汽车电子expert成长之路 目录 (1)嵌入式MCU与MPU的区分 (2)误区一:MCU的程序都是存储在片上Flash上,然 ...

  9. Java开发中经常使用到的几种WebService技术实现方案

    Java开发中经常使用到的几种WebService技术实现方案 随着异构系统互联需求的不断增加,WebService的重要性也日益彰显出来.凭借webservice,我们可以实现基于不同程序语言的项目 ...

最新文章

  1. linux之shell脚本学习篇一
  2. Tomcat启动分析server.xml
  3. 通过特征类型超参数控制权重类型
  4. Laravel提交POST请求报错
  5. oracle11g nid,Oracle工具之nid命令的使用
  6. Redhat安装tftp的方法
  7. python dbf 修改_在Python中将数据写入dbf时出错
  8. vscode的sftp插件同步失败no such file的问题
  9. [leetcode] 11.盛最多水的容器
  10. 兄弟打印机内存已满清零方法_打印机是如何清零的?兄弟打印机清零方法
  11. 2022最火的一款网盘赚钱系统源码 仿制蓝奏网盘/城通网盘/分享赚钱云盘系统/网盘VIP下载系统
  12. GIF动态图片分解,多帧动态图分解成多张静态图片
  13. 概率导论-马尔可夫相关
  14. 怎么把qlv格式转成mp4
  15. js中0.1+0.2为什么不等于0.3
  16. Android 打造炫目的圆形菜单 秒秒钟高仿建行圆形菜单
  17. C语言中 编译预处理命令的作用有哪些,C语言系列——预处理命令
  18. C++学习第一天(初步认识-程序流的分支-循环-数据类型)
  19. (转)网站建设的程序语言,Asp,Php,Jsp,Asp.Net优势比较
  20. Bug的由来,Bug为什么叫做Bug

热门文章

  1. [转载] python判断是否为json_Python判断变量是否为Json格式的字符串示例
  2. [转载] Python字符串解析
  3. [转载] 20个常用Python库及200个第三方库
  4. Java匹马行天下之学编程的起点——编程常识知多少
  5. Spring源码解析之BeanFactory
  6. nginx.conf添加lua.conf配置
  7. java.util.HashMap
  8. hdu 4059 The Boss on Mars 容斥
  9. 一步一步教你安装Nginx+PHP+Mysql
  10. 自定义ImageButton,实现快进快退功能