简介

虽然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的博客

欢迎关注我的公众号:程序那些事,更多精彩等着您!

troubleshoot之:使用JFR解决内存泄露的更多相关文章

  1. Android开发过程中使用弱引用解决内存泄露的习惯

    Java虽然有垃圾回收,但是仍然存在内存泄露,比如静态变量.缓存或其他长生命周期的对象引用了其他对象,这些被引用的对象就会长期不能被GC释放,导致内存泄露. 弱引用(WeakReference)是解决 ...

  2. Instruments检测解决内存泄露以及进行性能测试

    1.启动Xcode自带的Instruments.这里有两种方法启动. 方法一: 方法二: 2.选择Leaks选项.(该选项用来进行内存泄漏检测) 说明: Leaks:找到引发内存泄漏的起点. Time ...

  3. WPF WPF中解决内存泄露的几点提示与解决方法

    http://www.cnblogs.com/LastPropose/archive/2011/08/01/2124359.html 一直以来用WPF做一个项目,但是开发中途发现内存开销太大,用ANT ...

  4. C# HttpBrowser 跨进程访问,解决内存泄露问题

    #undef DEBUG using Microsoft.Win32; using Newtonsoft.Json; using System; using System.Collections.Ge ...

  5. 使用Xcode和Instruments调试解决iOS内存泄露

    转载自:http://www.uml.org.cn/mobiledev/201212123.asp  (或者http://www.cocoachina.com/bbs/read.php?tid=129 ...

  6. 解决iOS内存泄露

    文章很好,摘自:http://www.codeceo.com/article/xcode-instruments-ios-memory.html 虽然iOS 5.0版本之后加入了ARC机制,由于相互引 ...

  7. 【转】使用Xcode和Instruments调试解决iOS内存泄露

    原文网址:http://blog.csdn.net/totogo2010/article/details/8233565 虽然iOS 5.0版本之后加入了ARC机制,由于相互引用关系比较复杂时,内存泄 ...

  8. [转]使用Xcode和Instruments调试解决iOS内存泄露

    虽然iOS 5.0版本之后加入了ARC机制,由于相互引用关系比较复杂时,内存泄露还是可能存在.所以了解原理很重要. 这里讲述在没有ARC的情况下,如何使用Instruments来查找程序中的内存泄露, ...

  9. 使用Xcode和Instruments调试解决iOS内存泄露【转】

    转载自:http://blog.csdn.net/totogo2010/article/details/8233565 虽然iOS 5.0版本之后加入了ARC机制,由于相互引用关系比较复杂时,内存泄露 ...

随机推荐

  1. Ethical Hacking - GAINING ACCESS(10)

    CLIENT SIDE ATTACKS Use if server-side attacks fail. If IP is probably useless. Require user interac ...

  2. 【译】GraalVM—下一代JVM介绍

    原标题:GraalVM – an introduction to the next level JVM 随着Red Hat宣布Quarkus作为- 为GraalVM和HotSpot量身定制的下一代Ku ...

  3. html地图定位

    利用高德地图api实现简单的地图功能,包括定位,地图缩放,搜索,列表展示等等基础功能 <!doctype html> <html> <head> <meta ...

  4. git 缓存密码 unable to access... 403错误

    如果输入了 git config credential.helper 命令之后还是出现了osxkeychain, store 或者 cache 等,说明 git 的配置还是没有被清空,我参考了stac ...

  5. Linux系统中(CentOS 7)的用户和权限管理

    目录 用户和组 用户信息文件 用户密码信息 相关命令 用户管理 组管理 密码管理 权限管理 文件的详细信息 文件权限 相关命令 用户和组 用户信息文件 /etc/passwd (1 2 3 4 5 6 ...

  6. 图表可视化seaborn风格和调色盘

    seaborn是基于matplotlib的python数据可视化库,提供更高层次的API封装,包括一些高级图表可视化等工具. 使用seaborn需要先安装改模块pip3 install seaborn ...

  7. VSCode package.json warning: Problems loading reference 'https://json.schemastore.org/package'...

    报错内容 Problems loading reference 'https://json.schemastore.org/package': Unable to load schema from ' ...

  8. 真香!Linux 原来是这么管理内存的

    Linux 内存管理模型非常直接明了,因为 Linux 的这种机制使其具有可移植性并且能够在内存管理单元相差不大的机器下实现 Linux,下面我们就来认识一下 Linux 内存管理是如何实现的. 基本 ...

  9. numpy巩固

    导包 import numpy as np 创建二维数组 x = np.matrix([[1,2,3],[4,5,6]]) 创建一维数组 y = np.matrix([1,2,3,4,5,6]) x ...

  10. 读取 csv , xlsx 表格并添加总分列

    import pandas as pd import numpy as np data = pd.read_excel('学生成绩表.csv',columns = ['学号','姓名','高数','英 ...