Java OOM问题如何排查

2023-11-16

目录

什么是OOM

导致OOM问题的原因

排查手段

调优命令有哪些?JAVA虚拟机命令详解:

JAVA OOM问题排查记录

一、一个Java内存泄漏的排查案例


什么是OOM

OOM为out of memory的简称,来源于java.lang.OutOfMemoryError,指程序需要的内存空间大于系统分配的内存空间,OOM后果就是程序crash;可以通俗理解:程序申请内存过大,虚拟机无法满足,然后崩溃了。

导致OOM问题的原因   

1、内存加载的数据量太大:一次性从数据库取太多数据;
2、集合类中有对对象的引用,使用后未清空,GC不能进行回收;

3、代码中存在循环产生过多的重复对象;
4、启动参数堆内存值小。

为什么会没有内存了呢?原因不外乎有两点:

1)分配的少了:比如虚拟机本身可使用的内存(一般通过启动时的VM参数指定)太少。

2)应用用的太多并且用完没释放,浪费了。此时就会造成内存泄露或者内存溢出。

内存泄露:申请使用完的内存没有释放,导致虚拟机不能再次使用该内存,此时这段内存就泄露了,因为申请者不用了,而又不能被虚拟机分配给别人用。

内存溢出:申请的内存超出了JVM能提供的内存大小,此时称之为溢出。

最常见的OOM情况有以下四种:

  • java.lang.OutOfMemoryError: Java heap space ------>java堆内存溢出,此种情况最常见,一般由于内存泄露或者堆的大小设置不当引起。-----------重点是确认内存中的对象是否是必要的,先分清是因为内存泄漏(Memory Leak)还是内存溢出(Memory Overflow)。-------------如果是内存泄漏,可进一步通过工具查看泄漏对象到GCRoots的引用链。于是就能找到泄漏对象是通过怎样的路径与GC Roots相关联并导致垃圾收集器无法自动回收。---------如果不存在泄漏,那就应该检查虚拟机的参数(-Xmx与-Xms)的设置是否适当。(堆大小可以通过虚拟机参数-Xms,-Xmx等修改)。
  • java.lang.OutOfMemoryError: PermGen space 或 java.lang.OutOfMemoryError:MetaSpace ------>java方法区,(java8 元空间)溢出了,---------------方法区用于存放Class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。也有可能是方法区中保存的class对象没有被及时回收掉或者class信息占用的内存超过了我们配置。---------------一般出现于大量Class或者jsp页面,或者采用cglib等反射机制的情况,因为上述情况会产生大量的Class信息存储于方法区。此种情况可以通过更改方法区的大小来解决,使用类似-XX:PermSize=64m -XX:MaxPermSize=256m的形式修改。另外,过多的常量尤其是字符串也会导致方法区溢出。
  • java.lang.StackOverflowError ------> 不会抛OOM error,但也是比较常见的Java内存溢出。JAVA虚拟机栈溢出,一般是由于程序中存在死循环或者深度递归调用造成的,栈大小设置太小也会出现此种溢出。可以通过虚拟机参数-Xss来设置栈的大小。
  • 虚拟机栈和本地方法栈溢出
    如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常

排查手段

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

  • 如果是内存泄漏,可进一步通过工具查看泄漏对象到GC Roots的引用链。这样就能够找到泄漏的对象是通过怎么样的路径与GC Roots相关联的导致垃圾回收机制无法将其回收。掌握了泄漏对象的类信息和GC Roots引用链的信息,就可以比较准确地定位泄漏代码的位置

  • 如果不存在泄漏,那么就是内存中的对象确实必须存活着,那么此时就需要通过虚拟机的堆参数( -Xmx和-Xms)来适当调大参数;从代码上检查是否存在某些对象存活时间过长、持有时间过长的情况,尝试减少运行时内存的消耗

调优命令有哪些?JAVA虚拟机命令详解:

1、查看 Java进程------------jps 命令

命令jps类似于linux下的ps, 但它只用于列出Java的进程。

注意:jps命令类似于ps命今, 但是它只列出系统中所有的Java应用程序。 通过JPS命令可以方便地查看Java进程的启动类、 传入参数和Java虚拟机参数等信息。

2、查看虚拟机运行时信息----------jstat命令

        jstat是个可以用于观察Java应用程序运行时相关信息的工具。 它的功能非常强大, 可以通过它查看堆信息的详细情况。 jstat -gc 2972

jstat命令格式为: jstat [ option vmid [interval[s|ms] [count]] ]

使用命令如下: jstat -gcutil 20954 1000 意思是每1000毫秒查询一次,一直查。

gcutil的意思是已使用空间站总空间的百分比。

结果如下图:

3、导出堆到文件------jmap 命令

        一个多功能的命令,它可以生成Java程序的堆Dump文件, 也可以查看堆内对象实例的统计信息、 查看ClassLoader的信息以及finalizer队列。

        下例使用jmap生成PID为2972的Java程序的对象统计信息, 并输出到 s.txt文件中。 jmap -histo 2972 >c:\s.txt 
输出文件有如下结构:        
        jmap另一个更为重要的功能是得到Java程序的当前堆快照:

4、MAT工具----内存泄漏分析工具

  • Histogram可以列出内存中的对象,对象的个数以及大小。
  • Dominator Tree可以列出那个线程,以及线程下面的那些对象占用的空间。
  • Top consumers通过图形列出最大的object。
  • Leak Suspects通过MAT自动分析泄漏的原因----泄露嫌疑分析 

JAVA OOM问题排查记录

一、一个Java内存泄漏的排查案例

某个业务系统在一段时间突然变慢,我们怀疑是因为出现内存泄露问题导致的,于是踏上排查之路。

最常见的场景,假设你把new完的对象放在队列或者Map里,然后这个定时任务不停地添加这种对象,那最后肯定会OOM的。GC只能回收那些没有被引用的对象,而如果你个个都引用并且并不释放(方法结束或者主动置为null,或者将存放的集合销毁,没有设置过期时间),那再无敌的GC也帮不了你。所以不要把所有希望都寄托在GC上面。

        concurrenthashmap增加缓存删除设计

        实际开发中有个定时任务的应用,运行一段时间后就会OOM,通过jvm的各种监控来排查OOM的原因,特此记录在这里。

2.1 确定频繁Full GC现象

首先通过“虚拟机进程状况工具:jps”找出正在运行的虚拟机进程,最主要是找出这个进程在本地虚拟机的唯一ID(LVMID,Local Virtual Machine Identifier),因为在后面的排查过程中都是需要这个LVMID来确定要监控的是哪一个虚拟机进程。 同时,对于本地虚拟机进程来说,LVMID与操作系统的进程ID(PID,Process Identifier)是一致的,使用Windows的任务管理器或Unix的ps命令也可以查询到虚拟机进程的LVMID。

jps命令格式为: jps [ options ] [ hostid ]

使用命令如下: 使用jps:jps -l 使用ps:ps aux | grep tomat

找到你需要监控的ID(假设为20954),再利用“虚拟机统计信息监视工具:jstat”监视虚拟机各种运行状态信息。

jstat命令格式为: jstat [ option vmid [interval[s|ms] [count]] ]

使用命令如下: jstat -gcutil 20954 1000 意思是每1000毫秒查询一次,一直查。

gcutil的意思是已使用空间站总空间的百分比。 结果如下图:

 jstat执行结果

查询结果表明:这台服务器的新生代Eden区(E,表示Eden)使用了28.30%(最后)的空间,两个Survivor区(S0、S1,表示Survivor0、Survivor1)分别是0和8.93%,老年代(O,表示Old)使用了87.33%。程序运行以来共发生Minor GC(YGC,表示Young GC)101次,总耗时1.961秒,发生Full GC(FGC,表示Full GC)7次,Full GC总耗时3.022秒,总的耗时(GCT,表示GC Time)为4.983秒。

2.2 找出导致频繁Full GC的原因

分析方法通常有两种:

1)把堆dump下来再用MAT等工具进行分析,但dump堆要花较长的时间,并且文件巨大,再从服务器上拖回本地导入工具,这个过程有些折腾,不到万不得已最好别这么干。

2)更轻量级的在线分析,使用“Java内存影像工具:jmap”生成堆转储快照(一般称为headdump或dump文件)。

jmap命令格式: jmap [ option ] vmid

使用命令如下: jmap -histo:live 20954 查看存活的对象情况,如下图所示:

 存活对象

按照一位IT友的说法,数据不正常,十有八九就是泄露的。在我这个图上对象还是挺正常的。

我在网上找了一位博友的不正常数据,如下:

可以看出HashTable中的元素有5000多万,占用内存大约1.5G的样子。这肯定不正常。

2.3 定位到代码

定位带代码,有很多种方法,比如前面提到的通过MAT查看Histogram即可找出是哪块代码.

 2.4、jmap -dump:format=b,file=heapdump.bin pid

生成堆转储快照dump文件

sh-4.2# jmap -dump:format=b,file=heapdump.bin 10
Dumping heap to /a-one/bin/heapdump.bin ...
Heap dump file created

2.5、sz heapdump.bin

下载导出的堆快照dump文件,导入到MAT工具中

在这里插入图片描述

  • Histogram可以列出内存中的对象,对象的个数以及大小。
  • Dominator Tree可以列出那个线程,以及线程下面的那些对象占用的空间。
  • Top consumers通过图形列出最大的object。
  • Leak Suspects通过MA自动分析泄漏的原因
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java OOM问题如何排查 的相关文章

  • 如何使用 Java 以独立于平台的方式读取 Windows 共享驱动器?

    如何使用 Java 从 Windows 共享驱动器中读取数据 以便执行读取的 Java 代码可以在任何平台上同样正确地运行 您可以使用JCIFS http jcifs samba org 使用纯 Java 代码访问 SMB CIFS 共享
  • 如何修复安装 maven jar 插件依赖项时出现的错误?

    我正在将应用程序制作成 maven 中的 jar 文件 但是 当我从 Maven 中提取 jar 插件存储库并在终端中运行这三个命令时 mvn clean mvn compile mvn package 在 mvn package 中 我收
  • 将倒计时器从 10 秒改为 1 秒

    我有一个倒计时器 它以 1 秒的增量从 10000 毫秒倒计时到 0 毫秒 以使按钮在 10 秒后可单击 尽管计时器是准确的并且按照代码的说明执行操作 但我想更改秒的表示方式 但我不知道如何更改 java void startTimer c
  • 如何测试 Jersey REST Web 服务?

    我已经编写了一个 Restful Web 服务 并且必须使用 JUnit4 对其进行测试 我已经使用 Jersey Client 编写了一个客户端 但想知道我是否只能使用 junit4 测试我的服务 至少有人可以帮我提供样品吗 我的休息服务
  • Java JNDI 名称 java:/

    我正在遵循教程 https docs oracle com javase tutorial jndi index html https docs oracle com javase tutorial jndi index html 我的冒险
  • 枚举内的枚举

    这不是我被卡住的问题 而是我正在寻找一种简洁的方式来编写我的代码 本质上 我正在编写一个事件驱动的应用程序 用户触发事件 事件被发送到适当的对象 然后对象处理事件 现在我正在编写偶数处理程序方法 我希望使用 switch 语句来确定如何处理
  • 如何在不使用反射的情况下查看对象是否是数组?

    在Java中如何在不使用反射的情况下查看对象是否是数组 如何在不使用反射的情况下迭代所有项目 我使用 Google GWT 所以不允许我使用反射 我很想在不使用反射的情况下实现以下方法 private boolean isArray fin
  • Poi:从 xlsm 打开 Excel 文件后将其保存为 xlsx

    我正在编写一个java程序 它打开一个用户定义的excel文件 用数据填充它 然后将其保存在用户指定的路径 文件名和扩展名下 即使输入文件是 xlsm 也应该可以声明输出保存为 xlsx 但实际上是不可能的 如果我尝试使用下面的代码 打开文
  • 最终类中的静态函数是否隐式最终?

    我的问题基本上与this https stackoverflow com q 8766476 3882565一 但这是否也适用于static功能 我想了解 编译器是否处理所有static函数在一个final类为final 是否添加final
  • Java 7 中新的 JNLP 缺少项目警告是怎么回事?

    从 Java 6 切换到 Java 7 后 我的 JNLP 仍然工作正常 但它现在抛出一系列如下错误 Missing Application Name manifest attribute for http blah com app jar
  • 在仔细锁定但不受信任的代码上使用 Thread.stop()

    我知道Thread stop 已被弃用 并且有充分的理由 它通常不安全 但这并不意味着它是never安全 据我所知 在我想要使用它的上下文中它是安全的 而且 据我所知 我别无选择 上下文是一个两人策略游戏的第三方插件 以国际象棋为例 第三方
  • 抛出 UnsupportedOperationException

    因此其中一种方法的描述如下 public BasicLinkedList addToFront T data 该操作无效 对于排序列表 将生成 UnsupportedOperationException 使用消息 排序列表的操作无效 我的代
  • Java如何区分这些具有相同名称/签名的多个方法?

    今天我在追踪一个错误 我注意到我们的一个班级中有一些奇怪的事情 我删除了尽可能多的代码并发布在这里 class A static int obtainNumber return 42 static int obtainNumber retu
  • 当 javadoc 未附加到依赖项时,如何将 javadoc 引用到 Maven 的 eclipse 插件中的依赖项

    我在开发中使用 Eclipse Maven 和 Java 我使用 Maven 下载依赖项 jar 文件和 javadoc 如果可用 并使用 Maven 的 eclipse 插件为 Eclipse 生成 project 和 classpath
  • java中从视频中提取图像

    我想知道如何使用 JMF 从视频中提取图像 Player player Manager createRealizedPlayer cdi getLocator player start FrameGrabbingControl frameG
  • Maven编译错误:包不存在

    我正在尝试向现有企业项目添加 Maven 支持 这是一个多模块项目 前 2 个模块编译和打包没有问题 但我面临编译错误 我尝试在多个模块中使用相同的依赖项 我的结构是 gt parent gt pom xml gt module 1 gt
  • 使用 System.out.println 显示特殊字符

    我在将带有特殊字符的文本从网络服务发送或显示到数据库时遇到问题 在我的 Eclipse 上 我已将字符编码设置为 UTF 8 但它仍然不允许我显示字符 例如 像下面的代码一样简单的打印 String test System out prin
  • 带有客户端认证连接的 HTTP 客户端的 SOAP 请求超时异常

    我正在尝试点击具有客户端认证的网址并生成密钥 keytool genkey alias server keyalg RSA keystore example jks validity 10950 和密钥存储 keytool import t
  • 每次修改代码时都必须 mvn clean install

    我不是来自 Java 世界 但我必须为我的一个项目深入研究它 我不明白为什么每次修改或更新代码时 都必须 mvn clean install 来调试代码的最新版本 你知道为什么吗 尝试按Ctrl Shift F9 热插拔 有时会有所帮助
  • Java GridBagConstraints gridx 和 gridy 不工作?

    我正在尝试使用gridx and gridy定位我的按钮的约束 但它们不起作用 如果我改变gridx and gridy变量 什么也没有发生 如果我将填充更改为GridBagConstraints to NONE 仍然不行 我在这里错过了什

随机推荐

  • web前端开发自学书籍推荐这5本

    JavaScript权威指南 第6版 淘宝前端团队翻译的 看译者列表都是一堆大神 这本书又叫犀牛书 号称 Javascript 开发者的圣经 网上对此书评价很多 大概意思都是说这本书是一本 JavaScript 文档手册 没有完整看过一遍此
  • IMAP,POP3,SMTP协议

    1 IMAP 因特网报文存取协议IMAP Internet Message Access Protocol IMAP协议是由斯坦福大学的Mark Crispin教授在1986年开发的 后期版本是华盛顿州立大学进行开发的 IMAP4是TCP
  • spring-boot-starter-web(Web启动器)

    Spring MVC 是 Spring 提供的一个基于 MVC 设计模式的轻量级 Web 开发框架 其本身就是 Spring 框架的一部分 可以与 Spring 无缝集成 性能方面具有先天的优越性 是当今业界最主流的 Web 开发框架之一
  • ZYNQ FreeRTOS使用双网口笔记与爬坑

    正点原子领航者7020的开发板上有两个网口 想着用起来 上面一个是PS网口 一个是外挂在PL网口 使用vitis版本为2019 2 PL网口通过emio挂载在网络控制器1上 PS网口挂载在网络控制器0上 配置串口0 踩坑1 在vivado里
  • orCAD下设置不同的GND网络

    对 PCB设计 而言 其中最重要 也是最基础的 就是 电源与地GND 列举例子如下 i 首先 对 简单电路 而言 其中的 电源与地GND 只有2个 大部分情况下 其被命名为 VCC 和 GND ii 其次 对 稍复杂电路 而言 其必须对GN
  • HTTPS的工作过程

    HTTPS就是对HTTP进行了加密 因为要保证数据安全 就需要进行加密 网络中不再直接传输明文了 而是加密之后的密文 加密的方法有很多 但是整体可以分为两大类 对称加密和非对称加密 对称加密 对称加密其实就是通过同一个 密钥 把明文加密成密
  • MMSegmention官方文档阅读系列之三(MMSegmentation 算法库目录结构、了解配置文件信息)

    1 MMSegmentation 算法库目录结构的主要部分 1 mmsegmentation configs 配置文件 base 基配置文件 datasets 数据集相关配置文件 models 模型相关配置文件 schedules 训练日程
  • python 字典的增删改查

    由于字典并不能像列表一样切片 所以字典并没有添加单一元素的 方法 但可以通过以下方法添加 dictory 猫 cat 狗 dog 狼 holf print dictory dictory 猪 pig print dictory 添加多个元素
  • 装多系统的U盘启动盘的制作

    制作安装多系统USB启动盘 下载做启动盘软件 建议linux和windows都支持的软件做系统盘 推荐YUMI或UltraISO 本教程用的yumi UltraISO 百度搜 图形化界面 收费 但破解版很多 YUMI 简单 免安装 下载链接
  • 软件测试复习03:动态测试——白盒测试

    作者 非妃是公主 专栏 软件测试 个性签 顺境不惰 逆境不馁 以心制境 万事可成 曾国藩 文章目录 逻辑覆盖法 最常用 程序插桩技术 基本路径法 点覆盖 边覆盖 边对覆盖 主路径覆盖 符号测试 错误驱动测试 习题 白盒测试常用技术有 逻辑覆
  • 支付宝生活号开发配置以及相应的流程

    由于最近公司涉及到支付宝服务号升级生活号 故有机会接触支付宝生活号的开发 前期准备 申请支付宝生活号 步骤 说实话 支付宝生活号管理后台涉及功能太多 所以找到相应的配置项还是比较绕的 1 登录支付宝生活号平台 找到 开发者 这个菜单 2 进
  • ​第一个C#互联网客户端

    开发环境 本文涉及到的C 工程是基于 Visual Studio 2019 Ver16 10 建议更新到Visual Studio 2019最新的版本 准备工作 首先需要下载 WebRuntime 二进制包 TheUniverse下载地址
  • jar包替换class文件方法

    直接打成非压缩的jar包或war包 先将对应的jar或war包使用unzip解压出来 再用java的jar命令再打个非压缩的包 如 unzip myapp war d myapp cd myapp jar cvfM0 myapp war
  • 详解HTTP协议版本(HTTP/1.0、1.1、2.0、3.0区别)

    HTTP 1 0 1 1 2 0 3 0区别 HTTP1 0 无连接 队头阻塞 缓存 HTTP 1 1 特点 优缺点 长连接 管道传输 HTTP 1 0 比较 HTTP 1 1 HTTP协议层次结构图 HTTP 2 0 头部压缩 二进制格式
  • 运输层---运输层概述 UDP协议与TCP协议

    运输层是面向通信功能中的最高层 又是面向用户功能中的最底层 一 运输层的作用 AP n 代表各个进程 通讯并不是主机和主机之间的通信 实际上是应用进程之间的通信 IP协议的作用范围 主机和主机之间进行通信 端口 端口实际上是一个标识符 标志
  • 放大器内部结构原理图解

    晶体管放大器结构原理图解 功率放大器的作用是将来自前置放大器的信号放大到足够能推动相应扬声器系统所需的功率 就其功率来说远比前置放大器简单 就其消耗的电功率来说远比前置放大器为大 因为功率放大器的本质就是将交流电能 转化 为音频信号 当然其
  • 【好工具】Sourcegraph助你网页端快速浏览项目代码

    欢迎大家来到 好工具 专栏 这个专栏面向所有希望获得高效生产力工具的朋友 在这个专栏里 我们会和大家聊聊那些狂拽酷霸炫的生产力工具 相信大家一定我一样 茫然于庞大的工具海洋 却仍找不到称心的它来使用 这也是 好工具 专栏存在的意义 发掘 折
  • Unity UGUI的Image(图片)组件的介绍及使用

    UGUI的Image 图片 组件的介绍及使用 1 什么是UGUI的Image 图片 组件 UGUI的Image 图片 组件是Unity引擎中的一种UI组件 用于显示2D图像 它提供了一种简单而灵活的方式来在游戏中加载和显示图片 2 为什么要
  • 如何提高目标检测模型的置信度,提高mAP

    首先引用https blog csdn net Nire Yeyu article details 105403220 1 调小score threshold 这种方法属于见效快 但是治标不治本 在验证阶段直接调小score thresho
  • Java OOM问题如何排查

    目录 什么是OOM 导致OOM问题的原因 排查手段 调优命令有哪些 JAVA虚拟机命令详解 JAVA OOM问题排查记录 一 一个Java内存泄漏的排查案例 什么是OOM OOM为out of memory的简称 来源于java lang