如何查找 Java 内存泄漏

发布于 2024-07-04 20:09:57 字数 519 浏览 8 评论 0原文

如何发现 Java 中的内存泄漏(例如使用 JHat)? 我尝试在 JHat 中加载堆转储来进行基本查看。 但是,我不明白我应该如何找到根参考(ref) 或无论它叫什么。 基本上,我可以看出有几百兆字节的哈希表条目([java.util.HashMap$Entry 或类似的东西),但是地图到处都在使用......有什么方法可以搜索大地图,或者也许找到大型对象树的一般根?

[编辑] 好吧,到目前为止我已经阅读了答案,但我们只能说我是一个小气的混蛋(这意味着我对学习如何使用 JHat 更感兴趣,而不是支付 JProfiler 的费用)。 此外,JHat 始终可用,因为它是 JDK 的一部分。 当然,除非 JHat 除了暴力之外别无他法,但我不敢相信会出现这种情况。

另外,我认为我无法实际修改(添加所有地图大小的日志记录)并运行它足够长的时间以使我注意到泄漏。

How do you find a memory leak in Java (using, for example, JHat)? I have tried to load the heap dump up in JHat to take a basic look. However, I do not understand how I am supposed to be able to find the root reference (ref) or whatever it is called. Basically, I can tell that there are several hundred megabytes of hash table entries ([java.util.HashMap$Entry or something like that), but maps are used all over the place... Is there some way to search for large maps, or perhaps find general roots of large object trees?

[Edit]
Ok, I've read the answers so far but let's just say I am a cheap bastard (meaning I am more interested in learning how to use JHat than to pay for JProfiler). Also, JHat is always available since it is part of the JDK. Unless of course there is no way with JHat but brute force, but I can't believe that can be the case.

Also, I do not think I will be able to actually modify (adding logging of all map sizes) and run it for long enough for me to notice the leak.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

你列表最软的妹 2024-07-11 20:09:57

大多数时候,在企业应用程序中,给定的 Java 堆大于最大 12 到 16 GB 的理想大小。 我发现很难让 NetBeans 分析器直接在这些大型 Java 应用程序上工作。

但通常不需要这样做。 您可以使用jdk附带的jmap实用程序进行“实时”堆转储,即jmap将在运行GC后转储堆。 对应用程序执行一些操作,等待操作完成,然后进行另一个“实时”堆转储。 使用 Eclipse MAT 等工具加载堆转储,对直方图进行排序,查看哪些对象增加了,或者哪些对象最高,这将提供线索。

su  proceeuser
/bin/jmap -dump:live,format=b,file=/tmp/2930javaheap.hrpof 2930(pid of process)

这种方法只有一个问题: 巨大的堆转储,即使使用实时选项,也可能太大而无法转移到开发圈,并且可能需要具有足够内存/RAM 的计算机才能打开。

这就是类直方图出现的地方。 您可以使用 jmap 工具转储实时类直方图。 这只会给出内存使用情况的类直方图。基本上它不会有链接引用的信息。 例如,它可能会将 char 数组放在顶部。 下面是 String 类。 你必须自己画出联系。

jdk/jdk1.6.0_38/bin/jmap -histo:live 60030 > /tmp/60030istolive1330.txt

不像上面描述的那样,采用两个类直方图,而不是采用两个堆转储; 然后比较类别直方图并查看正在增加的类别。 看看是否可以将 Java 类与您的应用程序类相关联。 这将给出一个很好的提示。 这是一个 pythons 脚本,可以帮助您比较两个 jmap 直方图转储。 histogramparser.py

最后,像 JConolse 和 VisualVm 这样的工具对于查看内存随时间的增长至关重要,如果存在内存泄漏。 最后,有时你的问题可能不是内存泄漏,而是内存使用率过高。为此启用 GC 日志记录;使用更高级和新的压缩 GC,如 G1GC; 您可以使用 jdk 工具(例如 jstat)实时查看 GC 行为

jstat -gccause pid <optional time interval>

其他参考资料可通过 google 搜索 -jhat、jmap、Full GC、Humongous Allocation、G1GC

Most of the time, in enterprise applications the Java heap given is larger than the ideal size of max 12 to 16 GB. I have found it hard to make the NetBeans profiler work directly on these big java apps.

But usually this is not needed. You can use the jmap utility that comes with the jdk to take a "live" heap dump , that is jmap will dump the heap after running GC. Do some operation on the application, wait till the operation is completed, then take another "live" heap dump. Use tools like Eclipse MAT to load the heapdumps, sort on the histogram, see which objects have increased, or which are the highest, This would give a clue.

su  proceeuser
/bin/jmap -dump:live,format=b,file=/tmp/2930javaheap.hrpof 2930(pid of process)

There is only one problem with this approach; Huge heap dumps, even with the live option, may be too big to transfer out to development lap, and may need a machine with enough memory/RAM to open.

That is where the class histogram comes into picture. You can dump a live class histogram with the jmap tool. This will give only the class histogram of memory usage.Basically it won't have the information to chain the reference. For example it may put char array at the top. And String class somewhere below. You have to draw the connection yourself.

jdk/jdk1.6.0_38/bin/jmap -histo:live 60030 > /tmp/60030istolive1330.txt

Instead of taking two heap dumps, take two class histograms, like as described above; Then compare the class histograms and see the classes that are increasing. See if you can relate the Java classes to your application classes. This will give a pretty good hint. Here is a pythons script that can help you compare two jmap histogram dumps. histogramparser.py

Finally tools like JConolse and VisualVm are essential to see the memory growth over time, and see if there is a memory leak. Finally sometimes your problem may not be a memory leak , but high memory usage.For this enable GC logging;use a more advanced and new compacting GC like G1GC; and you can use jdk tools like jstat to see the GC behaviour live

jstat -gccause pid <optional time interval>

Other referecences to google for -jhat, jmap, Full GC, Humongous allocation, G1GC

相守太难 2024-07-11 20:09:57

有一些工具可以帮助您找到泄漏,例如 JProbe、YourKit、AD4J 或 JRockit Mission Control。 最后一个是我个人最了解的。 任何好的工具都应该让您深入到可以轻松识别泄漏的级别以及泄漏对象的分配位置。

使用 HashTables、Hashmaps 或类似的方法是 Java 中真正泄漏内存的少数方法之一。 如果我必须手动查找泄漏,我会定期打印 HashMap 的大小,然后从那里找到我添加项目但忘记删除它们的位置。

There are tools that should help you find your leak, like JProbe, YourKit, AD4J or JRockit Mission Control. The last is the one that I personally know best. Any good tool should let you drill down to a level where you can easily identify what leaks, and where the leaking objects are allocated.

Using HashTables, Hashmaps or similar is one of the few ways that you can acually leak memory in Java at all. If I had to find the leak by hand I would peridically print the size of my HashMaps, and from there find the one where I add items and forget to delete them.

伤痕我心 2024-07-11 20:09:57

好吧,总有一种技术含量较低的解决方案,即在修改地图时添加地图大小的日志记录,然后搜索日志以查找地图增长超出合理大小的日志。

Well, there's always the low tech solution of adding logging of the size of your maps when you modify them, then search the logs for which maps are growing beyond a reasonable size.

み零 2024-07-11 20:09:57

NetBeans 有一个内置的分析器。

NetBeans has a built-in profiler.

夏の忆 2024-07-11 20:09:57

您确实需要使用跟踪分配的内存分析器。 看看 JProfiler - 他们的“heap walker”功能很棒,并且它们与所有主要的 Java IDE 集成。 它不是免费的,但也不是那么昂贵(单个许可证 499 美元)——您将很快花费 500 美元的时间来努力使用不太复杂的工具来查找泄漏。

You really need to use a memory profiler that tracks allocations. Take a look at JProfiler - their "heap walker" feature is great, and they have integration with all of the major Java IDEs. It's not free, but it isn't that expensive either ($499 for a single license) - you will burn $500 worth of time pretty quickly struggling to find a leak with less sophisticated tools.

蘸点软妹酱 2024-07-11 20:09:57

您可以通过多次调用垃圾收集器后测量内存使用大小来发现:

Runtime runtime = Runtime.getRuntime();

while(true) {
    ...
    if(System.currentTimeMillis() % 4000 == 0){
        System.gc();
        float usage = (float) (runtime.totalMemory() - runtime.freeMemory()) / 1024 / 1024;
        System.out.println("Used memory: " + usage + "Mb");
    }

}

如果输出数量相等,则应用程序中没有内存泄漏,但如果您看到内存使用数量之间存在差异(数量增加),则存在内存泄漏您的项目中存在内存泄漏。 例如:

Used memory: 14.603279Mb
Used memory: 14.737213Mb
Used memory: 14.772224Mb
Used memory: 14.802681Mb
Used memory: 14.840599Mb
Used memory: 14.900841Mb
Used memory: 14.942261Mb
Used memory: 14.976143Mb

请注意,有时某些操作(例如流和套接字)需要一些时间来释放内存。 你不应该根据第一个输出来判断,你应该在特定的时间内测试它。

You can find out by measuring memory usage size after calling garbage collector multiple times:

Runtime runtime = Runtime.getRuntime();

while(true) {
    ...
    if(System.currentTimeMillis() % 4000 == 0){
        System.gc();
        float usage = (float) (runtime.totalMemory() - runtime.freeMemory()) / 1024 / 1024;
        System.out.println("Used memory: " + usage + "Mb");
    }

}

If the output numbers were equal, there is no memory leak in your application, but if you saw difference between the numbers of memory usage (increasing numbers), there is memory leak in your project. For example:

Used memory: 14.603279Mb
Used memory: 14.737213Mb
Used memory: 14.772224Mb
Used memory: 14.802681Mb
Used memory: 14.840599Mb
Used memory: 14.900841Mb
Used memory: 14.942261Mb
Used memory: 14.976143Mb

Note that sometimes it takes some time to release memory by some actions like streams and sockets. You should not judge by first outputs, You should test it in a specific amount of time.

耀眼的星火 2024-07-11 20:09:57

我使用以下方法来查找 Java 中的内存泄漏。 我使用 jProfiler 取得了巨大成功,但我相信任何具有图形功能的专用工具(差异更容易以图形形式分析)都可以工作。

  1. 启动应用程序并等待其进入“稳定”状态,此时所有初始化均已完成并且应用程序处于空闲状态。
  2. 多次运行怀疑产生内存泄漏的操作,以允许进行任何缓存、与数据库相关的初始化。
  3. 运行 GC 并拍摄内存快照。
  4. 再次运行该操作。 根据操作的复杂性和所处理的数据的大小,操作可能需要运行几次到多次。
  5. 运行 GC 并拍摄内存快照。
  6. 对 2 个快照运行差异并进行分析。

基本上,分析应该从最大的正差异开始,例如对象类型,并找出导致这些额外对象保留在内存中的原因。

对于在多个线程中处理请求的 Web 应用程序,分析变得更加复杂,但通用方法仍然适用。

我做了很多专门旨在减少应用程序内存占用的项目,这种通用方法加上一些特定于应用程序的调整和技巧总是效果很好。

I use following approach to finding memory leaks in Java. I've used jProfiler with great success, but I believe that any specialized tool with graphing capabilities (diffs are easier to analyze in graphical form) will work.

  1. Start the application and wait until it get to "stable" state, when all the initialization is complete and the application is idle.
  2. Run the operation suspected of producing a memory leak several times to allow any cache, DB-related initialization to take place.
  3. Run GC and take memory snapshot.
  4. Run the operation again. Depending on the complexity of operation and sizes of data that is processed operation may need to be run several to many times.
  5. Run GC and take memory snapshot.
  6. Run a diff for 2 snapshots and analyze it.

Basically analysis should start from greatest positive diff by, say, object types and find what causes those extra objects to stick in memory.

For web applications that process requests in several threads analysis gets more complicated, but nevertheless general approach still applies.

I did quite a number of projects specifically aimed at reducing memory footprint of the applications and this general approach with some application specific tweaks and trick always worked well.

萧瑟寒风 2024-07-11 20:09:57

这里的提问者,我不得不说,获得一个不需要 5 分钟来回答任何点击的工具可以更容易地发现潜在的内存泄漏。

由于人们建议使用几种工具(我只尝试过 Visual WM,因为我在 JDK 和 JProbe 试用版中得到了它),所以我认为我应该建议一个构建在 Eclipse 平台上的免费/开源工具,即内存分析器(有时称为 SAP 内存)分析器)可在 http://www.eclipse.org/mat/ 上找到。

这个工具真正酷的是,当我第一次打开它时,它对堆转储进行了索引,这使得它可以显示保留堆等数据,而无需为每个对象等待 5 分钟(几乎所有操作都比我尝试过的其他工具快得多) 。

当您打开转储时,第一个屏幕会向您显示一个饼图,其中包含最大的对象(计算保留的堆),并且可以快速向下导航到太大的对象以方便查看。 它还有一个“查找可能的泄漏嫌疑人”功能,我认为它可以派上用场,但由于导航对我来说已经足够了,所以我并没有真正了解它。

Questioner here, I have got to say getting a tool that does not take 5 minutes to answer any click makes it a lot easier to find potential memory leaks.

Since people are suggesting several tools ( I only tried visual wm since I got that in the JDK and JProbe trial ) I though I should suggest a free / open source tool built on the Eclipse platform, the Memory Analyzer (sometimes referenced as the SAP memory analyzer) available on http://www.eclipse.org/mat/ .

What is really cool about this tool is that it indexed the heap dump when I first opened it which allowed it to show data like retained heap without waiting 5 minutes for each object (pretty much all operations were tons faster than the other tools I tried).

When you open the dump, the first screen shows you a pie chart with the biggest objects (counting retained heap) and one can quickly navigate down to the objects that are to big for comfort. It also has a Find likely leak suspects which I reccon can come in handy, but since the navigation was enough for me I did not really get into it.

薄荷→糖丶微凉 2024-07-11 20:09:57

工具是一个很大的帮助。

然而,有时您无法使用工具:堆转储太大,导致工具崩溃,您试图对某些生产环境中的机器进行故障排除,而您只能通过 shell 访问,等等。

在这种情况下,它有助于了解 hprof 转储文件的方式。

寻找“站点开始”。 这会向您显示哪些对象使用最多的内存。 但这些对象并不仅仅按类型聚集在一起:每个条目还包含一个“跟踪”ID。 然后,您可以搜索“TRACE nnnn”以查看分配对象的堆栈的前几帧。 通常,一旦我看到对象的分配位置,我就会发现一个错误,然后我就完成了。 另请注意,您可以使用 -Xrunhprof 选项控制堆栈中记录的帧数。

如果您检查分配站点,没有发现任何错误,则必须开始从其中一些活动对象到根对象的向后链接,以找到意外的引用链。 这是工具真正有用的地方,但您可以手动执行相同的操作(好吧,使用 grep)。 不只有一个根对象(即不受垃圾回收影响的对象)。 线程、类和堆栈帧充当根对象,它们强引用的任何内容都是不可收集的。

要进行链接,请在 HEAP DUMP 部分中查找具有错误跟踪 ID 的条目。 这将带您到 OBJ 或 ARR 条目,其中显示十六进制的唯一对象标识符。 搜索该 id 的所有出现位置,以查找谁对该对象具有强引用。 沿着每条路径的分支向后追踪,直到找出泄漏位置。 明白为什么工具如此方便吗?

静态成员是内存泄漏的重犯。 事实上,即使没有工具,花几分钟检查静态 Map 成员的代码也是值得的。 地图可以变大吗? 有什么东西清理过它的条目吗?

A tool is a big help.

However, there are times when you can't use a tool: the heap dump is so huge it crashes the tool, you are trying to troubleshoot a machine in some production environment to which you only have shell access, etc.

In that case, it helps to know your way around the hprof dump file.

Look for SITES BEGIN. This shows you what objects are using the most memory. But the objects aren't lumped together solely by type: each entry also includes a "trace" ID. You can then search for that "TRACE nnnn" to see the top few frames of the stack where the object was allocated. Often, once I see where the object is allocated, I find a bug and I'm done. Also, note that you can control how many frames are recorded in the stack with the options to -Xrunhprof.

If you check out the allocation site, and don't see anything wrong, you have to start backward chaining from some of those live objects to root objects, to find the unexpected reference chain. This is where a tool really helps, but you can do the same thing by hand (well, with grep). There is not just one root object (i.e., object not subject to garbage collection). Threads, classes, and stack frames act as root objects, and anything they reference strongly is not collectible.

To do the chaining, look in the HEAP DUMP section for entries with the bad trace id. This will take you to an OBJ or ARR entry, which shows a unique object identifier in hexadecimal. Search for all occurrences of that id to find who's got a strong reference to the object. Follow each of those paths backward as they branch until you figure out where the leak is. See why a tool is so handy?

Static members are a repeat offender for memory leaks. In fact, even without a tool, it'd be worth spending a few minutes looking through your code for static Map members. Can a map grow large? Does anything ever clean up its entries?

窗影残 2024-07-11 20:09:57

我最近处理了应用程序中的内存泄漏问题。 在这里分享我的经验

垃圾收集器会定期删除未引用的对象,但它从不收集仍在引用的对象。 这就是可能发生内存泄漏的地方。

以下是一些查找引用对象的选项。

  1. 使用位于JDK/bin文件夹中的jvisualvm

选项:监视堆空间
输入图片description here

如果你看到堆空间不断增加,那么肯定存在内存泄漏。

要找出原因,您可以使用 sampler 下的 内存采样器

输入图片描述在这里

  1. 使用jmap(也可以在JDK/bin文件夹中找到)在不同时间跨度获取Java堆直方图应用

    jmap -histo ;   >   组织1.txt 
      

这里可以分析对象引用。 如果某些对象从未被垃圾回收,那就是潜在的内存泄漏。

您可以在本文中阅读内存泄漏的一些最常见原因:了解内存泄漏Java

I have recently dealt with a memory leak in our application. Sharing my experience here

The garbage collector removes unreferenced objects periodically, but it never collects the objects that are still being referenced. This is where memory leaks can occur.

Here is some options to find out the referenced objects.

  1. Using jvisualvm which is located in JDK/bin folder

Options : Watch Heap space
enter image description here

If you see that the heap space keep increasing, definitely there is a memory leak.

To find out the cause, you can use memory sampler under sampler .

enter image description here

  1. Get a Java heap histogram by using jmap ( which is also available in JDK/bin folder) in different time span of the application

    jmap -histo <pid> > histo1.txt
    

Here the object reference can be analyzed. If some of the objects are never garbage collected, that is the potential memory leak.

You can read the some of the most common cause of memory leak here in this article : Understanding Memory Leaks in Java

哥,最终变帅啦 2024-07-11 20:09:57

由于我们大多数人已经使用 Eclipse 来编写代码,为什么不使用 Eclipse 中的内存分析器工具(MAT)呢? 效果很好。

Eclipse MAT 是 Eclipse IDE 的一组插件,它提供了用于分析 Java 应用程序中的堆转储并识别内存问题的工具在应用程序中。

这可以帮助开发人员通过以下功能查找内存泄漏

  1. 获取内存快照(堆转储)
  2. 直方图
  3. 保留的堆
  4. 支配树
  5. 探索 GC 根检查器的路径
  6. 通用
  7. 内存反模式
  8. 对象查询语言

在此处输入图像描述

As most of us use Eclipse already for writing code, Why not use the Memory Analyser Tool(MAT) in Eclipse. It works great.

The Eclipse MAT is a set of plug-ins for the Eclipse IDE which provides tools to analyze heap dumps from Java application and to identify memory problems in the application.

This helps the developer to find memory leaks with the following features

  1. Acquiring a memory snapshot (Heap Dump)
  2. Histogram
  3. Retained Heap
  4. Dominator Tree
  5. Exploring Paths to the GC Roots
  6. Inspector
  7. Common Memory Anti-Patterns
  8. Object Query Language

enter image description here

难如初 2024-07-11 20:09:57

查看此截屏 关于使用 JProfiler 查找内存泄漏。
这是@Dima Malenko 答案的视觉解释。

注意:虽然JProfiler不是免费软件,但试用版可以处理当前情况。

Checkout this screen cast about finding memory leaks with JProfiler.
It's visual explanation of @Dima Malenko Answer.

Note: Though JProfiler is not freeware, But Trial version can deal with current situation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文