-
2021-03-19 09:23:47
测试代码,如下示例:
import java.util.ArrayList;
import java.util.List;
/**
* @Description 测试内存溢出, 启动时设置参数,最大堆内存为1m, 内存溢出时dump出内存文件 -Xmx1m -XX:+HeapDumpOutOfMemoryError
* @Author luzy
* @Date 2018/10/5 11:02
*/
public class testOOM {
public static void main(String[] args) {
List list=new ArrayList<>();
while (true){
list.add("1234567890");
}
}
}
运行时,设置jvm参数:-Xmx1m -XX:+HeapDumpOutOfMemoryError
意思是:最大堆内存为1m, 当内存溢出时dump出内存文件。
执行后会在classpath下产生 内存文件
接下来可以使用IBM HeapAnalyzer(下载地址),对内存文件进行分析。
执行如下命令启动IBM HeapAnalyzer
通过界面,打开dump文件
可以看到内存中对象所占用的内存比例
更多相关内容 -
Java内存溢出问题排查分析
2022-04-20 10:14:26项目运行过程中,我们可能会遇到Java内存溢出Out Of Memory。此时我们可以借助内存分析工具MAT(Memory Analyzer Tool),来定位是哪里出现了问题。 一、MAT(Memory Analyzer Tool) 下载地址:Eclipse Memory ...目录
前言
项目运行过程中,我们可能会遇到Java内存溢出Out Of Memory。此时我们可以借助内存分析工具MAT(Memory Analyzer Tool),来定位是哪里出现了问题。
一、MAT(Memory Analyzer Tool)
下载地址:Eclipse Memory Analyzer Open Source Project | The Eclipse Foundation
注意:JDK-8建议使用11版本,否则会提示版本不兼容
二、软件初识
解压后目录内有个MemoryAnalyzer.ini文件,该文件里面有个-Xmx参数。该参数表示最大内存占用量,默认为1024m。
建议修改为小于本机内存大小,大于要分析的dump文件大小-startup plugins/org.eclipse.equinox.launcher_1.5.0.v20180512-1130.jar --launcher.library plugins/org.eclipse.equinox.launcher.win32.win32.x86_64_1.1.700.v20180518-1200 -vmargs ### -Xmx1024my原本默认为1024m,此处我修改为4096m -Xmx4096m
三、捕获dump文件
首先在程序中模拟出一段内存溢出的逻辑:
@RequestMapping("/testOutOfMemory") @ResponseBody public void testOutOfMemory() throws Exception { String name = "Aikes"; for (int i = 0; i < 10000000; i++) { name += name; } System.out.println(name); }
然后启动项目,开始准备捕获dump文件。这里的捕获方式分为两种,一种是主动捕获,一种是被动捕获:
1、主动方式
顾名思义,当内存溢出发生后,通过指令的方式手机当前应用程序下的内存使用情况。
1、通过(Linux) ps -ef|grep find 或者 (Dos)netstat -ano|findstr 查找java程序运行的PID
2、使用指令收集dump:jmap -dump:format=b,file=路径/heapdump.hprof 查到的PID
注意:主动获取dump文件必须是一出现内存异常就获取dump文件,这样获取的文件信息才比较准确。如果无法及时获取,推荐通过第二种方式获取dump文件。
2、被动方式
该方式是启动Java服务时,增加额外参数。当程序发生内存溢出时自动收集dump文件:
1、-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/opt/oom/heapdump.hprof
配置好后,调用我们预先模拟的内存溢出接口
稍等片刻控制台开始打印日志,提示出现内存溢出并且已经收集到dump文件到指定目录:
四、分析dump文件
打开下载好的mat软件,通过file-open打开抓取到的dump文件(hprof文件)
点击切换视图,可以看到内存占用百分之八十是因为这个线程,继续点开发现是一个超大的字符串"AikesAikesAikes...."
此时我们已经发现了内存溢出的直接原因,接下来要寻找出现这个问题的代码在哪里。再返回到最初的大饼图,点击最下面的details。然后点击See stacktrace 堆叠追踪。
这里可以看到完整的堆栈信息,里面可以发现我们增加模拟溢出代码的那个Java文件,并且爆发内存溢出的代码行也可以对上,至此溢出分析结束。
总结
模拟的内存溢出针对性很强,并且我们抓取dump文件也很及时,所以在分析的时候很简单。实际使用过程中面对的陷阱很多,需要从诸多可能中排查幕后凶手。Mat工具功能还很多,目前只是粗略的使用,后续如果有新的发现会继续补充到博文中。
-
简记一次JAVA堆内存溢出排查过程
2022-05-18 21:41:31最近在进行一个模块的开发时,在测试环境中测试没问题,然后在发布到生产环境后,经常发生堆内存溢出的错误导致服务挂了,需要排查出错误的源头。 二、排查思路 加大堆内存参数。通过修改docker-compose.yml文件...一、背景
最近在进行一个模块的开发时,在测试环境中测试没问题,然后在发布到生产环境后,经常发生堆内存溢出的错误导致服务挂了,需要排查出错误的源头。
二、排查思路
- 加大堆内存参数。通过修改docker-compose.yml文件参数调大jvm的堆内存大小。并且把错误发生时的快照保存进文件,以便重现时进行分析。(本模块是基于容器化部署)
environment: - JAVA_OPTIONS=-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp -Xmx4096m
- 当加大堆内存后,仍然发生了堆内存溢出,此时我们就需要获取到对应的内存快照进行分析。此时我们可以在/tmp目录下获取到对应生成的文件java_pid1.hprof。
- 选择一款合适的jvm内存分析软件对java_pid1.hprof进行解析分析。
三、jvm分析软件
本次排查过程采用的软件是jvisualvm,这是一款jdk8的bin目录下自带的一个分析工具,使用这个工具我们可以用来分析hprof文件。进入bin目录后,使用jvisualvm命令即可打开该软件
cd /usr/bin jvisualvm
进入软件后,点击左上角的图标,即可装入hprof文件
选择生成的hprof文件装入后:
然后点击查看异常抛出的线程。
然后就在该线程下找到了一个熟悉的方法,发现原来有个地方一次性从数据库中查询了几十万的数据返回,导致一下子就把堆内存撑爆了,然后找到类似的地方也修改了。之所以在测试环境中没问题,是因为测试环境数据量不多。至此问题排查结束,修改对应的代码就完事了。
- 加大堆内存参数。通过修改docker-compose.yml文件参数调大jvm的堆内存大小。并且把错误发生时的快照保存进文件,以便重现时进行分析。(本模块是基于容器化部署)
-
Java Web项目内存溢出问题排查
2020-05-08 18:32:07线上的一个spring boot项目每两个周会出现系统卡死,不能正常提供api服务,重启后恢复。经过查看日志发现大量的“java.lang.OutOfMemoryError: GC overhead limit exceeded”日志。这个异常的官方解释: Exception ...线上的一个spring boot项目每两个周会出现系统卡死,不能正常提供api服务,重启后恢复。经过查看日志发现大量的“java.lang.OutOfMemoryError: GC overhead limit exceeded”日志。这个异常的官方解释:
Exception in thread thread_name: java.lang.OutOfMemoryError: GC Overhead limit exceeded
Cause: The detail message “GC overhead limit exceeded” indicates that the garbage collector is running all the time and Java program is making very slow progress. After a garbage collection, if the Java process is spending more than approximately 98% of its time doing garbage collection and if it is recovering less than 2% of the heap and has been doing so far the last 5 (compile time constant) consecutive garbage collections, then a java.lang.OutOfMemoryError is thrown. This exception is typically thrown because the amount of live data barely fits into the Java heap having little free space for new allocations.
Action: Increase the heap size. The java.lang.OutOfMemoryError exception for GC Overhead limit exceeded can be turned off with the command line flag -XX:-UseGCOverheadLimit.JVM用了98%的时间进行垃圾回收,而只得到2%可用的内存,频繁的进行内存回收。
结合现象,可以推测程序中某些实例的数量在缓慢的增长,但是一直不能被回收。虽然异常信息不是常见的“java.lang.OutOfMemoryError: Java heap space”,但是原因却是相同的。那我就开始查找原因吧!先说一下笔者的思路:
1、从生成获取dump文件
2、使用jvisualvm.exe或Eclipse Memory Analyzer(MAT)进行内存分析jvisualvm.exe(JDK自带的工具)
Eclipse Memory Analyzer(第三方的工具,可不依赖eclipse单独下载)3、结合业务代码进行问题定位
4、提出修改方案获取dump文件
可以直接在启动脚本中添加如下参数,在程序内存溢出时自动生成dump文件
-XX:+HeapDumpOnOutOfMemoryError # 告诉jvm内存溢出时生成dump文件 -XX:HeapDumpPath=/tmp/dump # 指定dump的路径
这个案发现场的第一手资料显然需要漫长等待过程,不如立即生成一份dump文件
先找到程序的pid(笔者这里时11008)然后使用下面的命令在当前目录执行:/opt/jdk/bin/jmap -dump:format=b,file=20200508.dump 11008
内存分析
如果dump文件比较小,直接使用jdk安装路径/bin/jvisualvm.exe来分析,运行jvisualvm.exe,然后点击File - 装入
如果文件很大,比如笔者dump文件是2G左右,那就需要使用更强大的MAT工具。打开MAT之前,根据实际dump文件大小,调一下内存大小。
启动MAT,点击File - Open Heap Dump
这个工具很快就能加载完成,默认显示Overview界面
笔者常用的三个功能如上图标识,先借助Leak Suspects自动分析生成一个报告:
根据自动分析推测com.sun.jmx.mbeanserver.JmxMBeanServer这个对象占用了已消耗空间的91.93%,但这个类明显不是我们业务对象。追根溯源,我们下一步就需要找出这个类和业务代码的关系。
使用Dominator Tree功能分析对象之间的支配关系。
在支配关系树种,我们依次展开Retained Heap值最大的那个支配者,最后发现是“org.apache.kafka.common.network.KafkaChannel”持有,最终也没追溯到我们自己写的业务代码。线索断了。。。。Retained Heap:表示因为这个对象,导致所有引用这个对象而不能被回收的内存大小
虽然通过MAT我们没法定位到业务代码,但是也提供一个思路:
去业务代码中review与kafka相关的逻辑。
笔者发现业务代码中与kafka相关的逻辑,只有使用kafaka-client来连接kafka服务器,而当前这个应用,只是测试连通型,并且有个定时任务每小时会执行一次这个测试。会不会是这个测试代码写的有问题,导致对象没有被释放,导致的呢?
果然如此,笔者找到的代码片段如下:public Integer testConnectionKafka(Long clusterId) { // .... // .... // .... KafkaConsumer<Object, Object> kafkaConsumer = new KafkaConsumer<>(props); try { kafkaConsumer.listTopics(); } catch (Exception ex) { throw new QdamException("KAFKA连接失败: " + ex.getMessage()); } return SUCCESS; }
这里每次调用testConnectionKafka()方法都会创建一个kafkaConsumer, 但是执行完这个方法,并没有关闭。笔者有理由怀疑可能和这里有关。修改方案也很简单,增加kafkaConsumer.close()即可。
} finally { kafkaConsumer.close(); }
修改后上线观察…
-
java线上内存溢出问题排查步骤
2021-02-28 18:51:57一般线上遇到比较头疼的就是OOM内存溢出问题,我们都会先看错误日志,如果错误日志能够定位出哪个类对象导致内存溢出,那么我们只需要针对问题修改bug就好。但是很多时候我们单凭日志无法定位出内存溢出问题,那么... -
java 排查内存溢出的方法及代码处
2021-10-21 16:20:56一、修改一下自己的程序/tomcat配置,将内存调小一点容易调试 -XX:+HeapDumpOnOutOfMemoryError -Xms20m -Xmx20m 二、写一个死循环测试 1、 @Test public void memoryTest(){ List<ContractTmpt> ... -
Java内存溢出排查方法,面试总结+详细解答!
2021-07-27 12:04:52重点问了Java线程锁:synchronized 和ReentrantLock相关的底层实现 线程池的底层实现以及常见的参数 数据结构基本都问了一遍:链表、队列等 Java内存模型:常问的JVM分代模型,以及JDK1.8后的区别,最后还问了JVM... -
java 内存溢出 栈溢出的原因与排查方法
2020-12-23 08:34:061、 内存溢出的原因是什么?内存溢出是由于没被引用的对象(垃圾)过多造成JVM没有及时回收,造成的内存溢出。如果出现这种现象可行代码排查:一)是否应用中的类中和引用变量过多使用了Static修饰 如public staitc ... -
linux下Java内存溢出排查
2021-05-15 06:51:121、查询gc情况(每1秒钟打印一次gc情况)jstat -gcutil pid 1000:1查询结果含义:S0:幸存区1占用率S1:幸存区2占用率E:Eden区占用率O:老年区占用率M:元数据区(java8,相当于java7及之前的永久代的概念)使用大小ccs:压缩后... -
【java内存溢出问题排查】堆外和堆内 内存异常消耗排查方式
2022-06-17 14:14:31java 内存溢出排查 -
JVM堆内存溢出排查
2021-12-05 22:13:26是否有小伙伴在碰到了OOM的时候,抓耳挠腮,不知如何下手,通过这篇保姆级的教程,可以教会你快速定位堆内存溢出的bug,本篇讲述的主题是生成dump文件以及通过Visual VM分析dump文件 -
java jvm oom 内存溢出排查过程
2022-01-12 19:16:52一、问题定位 直接导出了dump文件 ...二 为何发生了内存泄漏 这个问题,就得探究LIVE_SET是个啥东西? 撸了一圈源码后,有以下收获: 1、它是netty的类:io.netty.util.internal.ObjectCleaner 下面的一个 -
关于Java Tomcat 内存溢出排查
2018-07-17 11:14:20网站不知道什么时候,开始内存飙升,从 Tomcat 启动后,初始内存占用4%~5% ...一、定位造成内存溢出可能存在的问题 io流操作文档没关闭流。 往一个静态集合变量里一直压栈。 连接没释放。 Java队列没消耗。 ... -
linux java进程内存溢出崩掉问题排查
2021-07-28 09:15:07linux java进程内存溢出 1、ps -ef | grep java—查看进程 2、jstat -gc pid 2000 --查看进程的垃圾回收情况,每2000毫秒输出一次 3、jmap -histo pid | head -n 100 查看pid中最占内存的对象,包括创建测次数和大小 -
Java内存泄漏的排查
2021-09-06 15:06:591.内存溢出 一种通俗的说法。 1、内存溢出:你申请了10个字节的空间,但是你在这个空间写入11或以上字节的数据,出现溢出。 2、内存泄漏:你用new申请了一块内存,后来很长时间都不再使用了(按理应该释放),但是... -
内存溢出排查命令
2021-03-22 08:05:38可以先用top命令查询出占用内存最多的进程,然后使用下面指令分析占用内存较大的代码查看进程的内存镜像信息jmap -572 // 572表示的是进程id显示java堆详细信息jmap -heap -572 // 572表示的是进程id显示堆中对象的... -
java内存溢出 栈溢出的原因与排查方法
2021-01-26 18:55:19java内存溢出 原因与排查方法 1、 内存溢出的原因是什么? 内存溢出是由于没被引用的对象(垃圾)过多造成JVM没有及时回收,导致剩余的内存不够用,造成的内存溢出。如果出现这种现象可行代码排查: 一)是否应用... -
记录一次Java内存溢出排查过程
2020-04-23 17:32:02这两天公司的一个程序出现问题,频繁出现内存溢出错误OutOfMemory:GC overhead limit exceeded. 虽然知道这个错误的原因是因为Java虚拟机在频繁进行垃圾回收,使用了98%的时间进行垃圾回收,但是实际回收了不到2%的... -
【Java面试】Java 内存溢出 栈溢出的原因与排查方法
2022-03-24 15:38:251、 内存溢出的原因是什么? 内存溢出是由于没被引用的对象(垃圾)过多造成JVM没有及时回收,造成的内存溢出。如果出现这种现象可行代码排查: 一)是否App中的类中和引用变量过多使用了Static修饰 如public staitc... -
Java 内存溢出排查
2018-10-23 20:24:17因此,OOM 的排查及定位是每个 Java 工程师都必备的技能。 所遇到的问题 在使用 scala 开发的一个 web 服务,在用户使用中,经常出现: java.lang.OutOfMemoryError: Java heap space 。而且还束手无策,每次都只能... -
jvm内存溢出区域和排查方法
2021-03-13 17:48:41目录首先我们需要掌握什么是内存溢出和内存泄漏内存泄漏:即声明的对象无法被回收,一直存在于内存中,使得占用的内存就像被泄漏消失了一样内存溢出:即剩余可用的内存空间过小,无法分配出下一步工作需要的内存。... -
使用jvisualvm.exe工具查看java项目内存溢出(堆溢出)--制造内存溢出
2021-02-28 06:43:36在查看内存溢出的时候,我们需要明白,堆溢出和持久代溢出,他们不一样,说到内存泄漏,我们就需要明白,内存中 年老代和新生代,和持久代,这3块的数据自己的理解:new了一个对象,会进入到堆里面,先放到年轻代中 ... -
Java内存溢出排查(必看)
2019-05-17 10:58:44因此,OOM的排查及定位是每个Java工程师都必备的技能。 所遇到的问题 在使用scala开发的一个web服务,在用户使用中,经常出现:java.lang.OutOfMemoryError: Java heap space。而且还束手无策,每次都只能重启服务... -
【Java内存溢出排查】gc监测以及内存突增问题排查
2020-02-29 22:35:45文档:【Java内存溢出排查】测试环境服务器挂... 链接:http://note.youdao.com/noteshare?id=783e7ec89950f4167867ef3ef33470b6&sub=48AEFC6FDECB4C60869FAA5FABF57AB0 通过以下命令信息可以确定是内存溢出... -
定位排查Java线上内存溢出问题(服务重启,没有捕获到日志)
2021-09-07 15:51:14一、场景 线上项目device服务模块内存不断上涨...内存溢出问题因为JVM内存分配不够大导致的,调大JVM的内存可以短暂解决此问题,但解决不了根本问题,需要从代码层去定位排查 二、Java启动参数分析(调试参数)... -
java内存溢出-Memory Analyzer(MAT)排查工具的简单使用
2021-04-10 15:50:21Memory Analyzer(MAT)是一款内存分析工具,可以通过该工具打开.hprof文件进行分析内存溢出的原因。 在开始介绍这款工具使用前,先了解一下如何获取.hprof文件,首先我们需要在tomcat.service文件中加入内存溢出的...