troubleshoot之:使用JFR解决内存泄露
简介
虽然java有自动化的GC,但是还会有内存泄露的情况。当然java中的内存泄露跟C++中的泄露不同。
在C++中所有被分配的内存对象都需要要程序员手动释放。但是在java中并不需要这个过程,一切都是由GC来自动完成的。那么是不是java中就没有内存泄露了呢?
要回答这个问题我们首先需要界定一下什么是内存泄露。如果说有时候我们不再使用的对象却不能被GC释放的话,那么就可以说发生了内存泄露。
内存泄露的主要原因就是java中的对象生命周期有长有短。如果长生命周期的对象引用了短生命周期的对象,就有可能造成事实上的内存泄露。
一个内存泄露的例子
我们举一个内存泄露的例子,先定义一个大对象:
public class KeyObject { List<String> list = new ArrayList<>(200); }
然后使用它:
public class TestMemoryLeak { public static HashSet<Object> hashSet= new HashSet(); public static void main(String[] args) throws InterruptedException { boolean flag= true; while(flag){ KeyObject keyObject= new KeyObject(); hashSet.add(keyObject); keyObject=null; Thread.sleep(1); } System.out.println(hashSet.remove(new KeyObject())); } }
在这个例子中,我们将new出来的KeyObject对象放进HashSet中。
然后将keyObject置为空。
但是因为类变量hashSet还保留着对keyObject的引用,所以keyObject对象并不会被回收。
注意,最后一行我们加了一个hashSet.remove的代码,来使用类变量hashSet。
为什么要这样做呢?这样做是为了防止JIT对代码进行优化,从而影响我们对内存泄露的分析。
使用JFR和JMC来分析内存泄露
Flight Recorder(JFR)主要用来记录JVM的事件,我们可以从这些事件中分析出内存泄露。
可以通过下面的指令来开启JFR:
java -XX:StartFlightRecording
当然我们也可以使用java神器jcmd来开启JFR:
jcmd pid JFR.dump filename=recording.jfr path-to-gc-roots=true
这里我们使用JMC来图形化分析一下上面的例子。
开启JMC,找到我们的测试程序,打开飞行记录器。
可以看到我们的对象在飞行记录器期间分配了4MB的内存,然后看到整体的内存使用量是稳步上升的。
我们什么时候知道会有内存泄露呢?最简单的肯定就是OutOfMemoryErrors,但是有些很隐蔽的内存泄露会导致内存使用缓步上涨,这时候就需要我们进行细致的分析。
通过分析,我们看到内存使用在稳步上涨,这其实是很可疑的。
接下来我们通过JVM的OldObjectSample事件来分析一下。
OldObjectSample
OldObjectSample就是对生命周期比较长的对象进行取样,我们可以通过研究这些对象,来检查潜在的内存泄露。
这里我们关注一下事件浏览器中的Old Object Sample事件,我们可以在左下方看到事件的详情。
或者你可以使用jfr命令直接将感兴趣的事件解析输出:
jfr print --events OldObjectSample flight_recording_1401comflydeanTestMemoryLeak89268.jfr > /tmp/jfrevent.log
我们看一个具体的输出Sample:
jdk.OldObjectSample { startTime = 19:53:25.607 allocationTime = 19:50:51.924 objectAge = 2 m 34 s lastKnownHeapUsage = 3.5 MB object = [ java.lang.Object[200] ] arrayElements = 200 root = N/A eventThread = "main" (javaThreadId = 1) stackTrace = [ java.util.ArrayList.<init>(int) line: 156 com.flydean.KeyObject.<init>() line: 11 com.flydean.TestMemoryLeak.main(String[]) line: 17 ] }
lastKnownHeapUsage是heap的使用大小,从日志中我们可以看到这个值是一直在增加的。
allocationTime表示的是这个对象分配的时间。
startTime表示的是这个对象被dump的时间。
object表示的是分配的对象。
stackTrace表示的是这个对象被分配的stack信息。
注意,如果需要展示stackTrace信息,需要开启-XX:StartFlightRecording:settings=profile选项。
从上面的日志我们可以分析得出,main方法中的第17行,也就是 KeyObject keyObject= new KeyObject(); 在不断的创建新的对象。
从而我们可以进行更深层次的分析,最终找到内存泄露的原因。
总结
本文通过JFR和JMC的使用,介绍了如何分析内存泄露。希望大家能够喜欢。
本文作者:flydean程序那些事
本文链接:http://www.flydean.com/jvm-diagnostic-memory-leak/
本文来源:flydean的博客
欢迎关注我的公众号:程序那些事,更多精彩等着您!

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
json从立地到成佛
声明 本文原创作者bigsai(同公众号),本文以浅显易懂的方式给大家讲解自己所认知的json,如果有错误或者不准确地方还请大家给出指正,另外本文以关卡课程的方式在博学谷也是免费开放的,大家也可通过关卡方式学习。链接地址。 诞生于JavaScript,json的前世今生 json含义 在开始之前,问个问题,什么是json? a:我猜它应该是某一门高深的技术(语重心长) b:json这个词为啥谷歌翻译?是啥新词语嘛?是不是搞错了哟?(底气十足) c:json这个我听过,我只知道他是一种很轻量存储结构,但具体真的不太懂(轻声) json它不是一个原有单词,其实是4个单词JavaScript Object Notation(JavaScript对象表示)的简写,是一种轻量级的文本数据交换格式,并且json独立于语言(使用JavaScript语法描述对象),很多编程语言都支持json。 json 已成为当前服务器与 web 应用之间数据传输的公认标准。 json诞生 问个问题,json是如何诞生的呢? 这个问题首先由于互联网应用之间需要传输数据,且很多跨平台的程序需要交互,只能采取纯文本方式的...
- 下一篇
troubleshoot之:分析OutOfMemoryError异常
简介 java.lang.OutOfMemoryError应该java应用程序中非常常见的一个的错误了。 那么OutOfMemoryError产生的原因是什么呢?我们怎么去查找相应的错误呢?一起来看看吧。 OutOfMemoryError 先看一下OutOfMemoryError的定义,OutOfMemoryError继承自VirtualMachineError,它是Error的一种,表示的是应用程序无法处理的异常,一般情况下会导致虚拟机退出。 public class OutOfMemoryError extends VirtualMachineError { @java.io.Serial private static final long serialVersionUID = 8228564086184010517L; /** * Constructs an {@code OutOfMemoryError} with no detail message. */ public OutOfMemoryError() { super(); } /** * Constructs an {...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS7设置SWAP分区,小内存服务器的救世主
- CentOS7安装Docker,走上虚拟化容器引擎之路
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- CentOS7编译安装Gcc9.2.0,解决mysql等软件编译问题
- Docker使用Oracle官方镜像安装(12C,18C,19C)
- CentOS7,8上快速安装Gitea,搭建Git服务器
- CentOS7编译安装Cmake3.16.3,解决mysql等软件编译问题
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- SpringBoot2全家桶,快速入门学习开发网站教程
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装