浅谈JVM之使用JFR解决内存泄露

 更新时间:2021年06月03日 09:36:02   作者:flydean  
内存泄露的主要原因就是java中的对象生命周期有长有短。如果长生命周期的对象引用了短生命周期的对象,就有可能造成事实上的内存泄露。本文将介绍JVM之使用JFR解决内存泄露。

简介

虽然java有自动化的GC,但是还会有内存泄露的情况。当然java中的内存泄露跟C++中的泄露不同。

在C++中所有被分配的内存对象都需要要程序员手动释放。但是在java中并不需要这个过程,一切都是由GC来自动完成的。那么是不是java中就没有内存泄露了呢?

要回答这个问题我们首先需要界定一下什么是内存泄露。如果说有时候我们不再使用的对象却不能被GC释放的话,那么就可以说发生了内存泄露。

一个内存泄露的例子

我们举一个内存泄露的例子,先定义一个大对象:

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(); 在不断的创建新的对象。

从而我们可以进行更深层次的分析,最终找到内存泄露的原因。

以上就是浅谈JVM之使用JFR解决内存泄露的详细内容,更多关于JVM之使用JFR解决内存泄露的资料请关注脚本之家其它相关文章!

相关文章

  • Java语言实现基数排序代码分享

    Java语言实现基数排序代码分享

    这篇文章主要介绍了Java语言实现基数排序代码分享,具有一定借鉴价值,需要的朋友可以参考下。
    2017-12-12
  • Java8新特性之方法引用的实践指南

    Java8新特性之方法引用的实践指南

    这篇文章主要给大家介绍了关于Java8新特性之方法引用的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • springboot结合JWT实现单点登录的示例

    springboot结合JWT实现单点登录的示例

    本文主要介绍了springboot结合JWT实现单点登录的示例,包括生成Token、验证Token及使用Redis存储Token,具有一定的参考价值,感兴趣的可以了解一下
    2025-01-01
  • 使用@Validated和@Valid 解决list校验的问题

    使用@Validated和@Valid 解决list校验的问题

    这篇文章主要介绍了使用@Validated和@Valid 解决list校验的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-10-10
  • java版简单的猜数字游戏实例代码

    java版简单的猜数字游戏实例代码

    猜数字游戏是一款经典的游戏,该游戏说简单也很简单,说不简单确实也很难,那么下面这篇文章主要给大家介绍了java版简单的猜数字游戏的相关资料,文中给出了详细的实现分析和示例代码供大家参考学习,需要的朋友们下面来一起看看吧。
    2017-05-05
  • java搭建ftp/sftp进行数据传递的全过程

    java搭建ftp/sftp进行数据传递的全过程

    ftp是一种文件传输协议,让客户端和服务端能够互相传递文件,图片等数据,sftp也是一种文件传输协议,但是相比较而言要比ftp安全性更好些,但是也有缺点就是传输效率低
    2021-07-07
  • java mybatis框架配置详解

    java mybatis框架配置详解

    在本篇文章里小编给大家整理的是一篇关于java mybatis框架配置详解内容,对此有兴趣的朋友们可以参考下。
    2021-02-02
  • 使用SpringAOP实现公共字段填充功能

    使用SpringAOP实现公共字段填充功能

    在新增员工或者新增菜品分类时需要设置创建时间、创建人、修改时间、修改人等字段,在编辑员工或者编辑菜品分类时需要设置修改时间、修改人等字段,这些字段属于公共字段,本文将给大家介绍使用SpringAOP实现公共字段填充功能,需要的朋友可以参考下
    2024-08-08
  • Spring Boot 2.X整合Spring-cache(让你的网站速度飞起来)

    Spring Boot 2.X整合Spring-cache(让你的网站速度飞起来)

    这篇文章主要介绍了Spring Boot 2.X整合Spring-cache(让你的网站速度飞起来),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • Java中ArrayList的8种浅拷贝方式示例代码

    Java中ArrayList的8种浅拷贝方式示例代码

    这篇文章主要介绍了Java中ArrayList的8种浅拷贝方式的相关资料,讲解了Java中ArrayList的浅拷贝概念,并详细分享了八种实现浅拷贝的方法,可以帮助读者更好地理解和选择合适的浅拷贝方法,需要的朋友可以参考下
    2025-01-01

最新评论