你如何在Java中找到内存泄漏(例如,使用JHat)?我试图在JHat中加载堆转储以获得基本外观.但是,我不明白我应该如何能够找到根引用(ref)或其所谓的.基本上,我可以说有几百兆字节的哈希表条目([java.util.HashMap $ Entry或类似的东西),但地图遍布整个地方...有没有办法搜索大地图,或者可能找到大型对象树的一般根源?
[编辑]好的,到目前为止我已经阅读了答案,但我们只是说我是一个廉价的混蛋(这意味着我对学习如何使用JHat更感兴趣而不是支付JProfiler).此外,JHat始终可用,因为它是JDK的一部分.除非当然没有办法与JHat合作但是蛮力,但我无法相信可能是这样.
此外,我认为我不能实际修改(添加所有地图大小的记录)并运行它足够长的时间让我注意到泄漏.
我正在尝试一个工具jhat来测试我的java内存使用情况.它读入堆转储文件并将信息打印为html.但是,表格显示如下:
Class Instance Count Total Size
class [B 36585 49323821
class [Lcom.sun.mail.imap.IMAPMessage; 790 16254336
class [C 124512 12832896
class [I 23080 11923504
class [Ljava.lang.Object; 13614 6664528
class java.lang.String 108982 2179640
class java.lang.Integer 219502 878008
Run Code Online (Sandbox Code Playgroud)
什么是[B [C等级?
我有一个6.5GB的Hprof文件,使用该-XX:-HeapDumpOnOutOfMemoryError选项由64位JVM转储.我把它放在一台16GB的64位机器上,并且我试图将它放入jhat,但它一直在耗尽内存.我试过传递jvm args以获得最小设置,但它拒绝任何最小值,并且在达到最大值之前似乎耗尽了内存.
jvm耗尽内存会使堆积如此之大以至于无法将其加载到具有两倍ram的盒子上,这似乎有点愚蠢.有没有办法让这个运行,或可能摊销分析?
在我的工作中,我们遇到了难以重现的OOM问题.或者,更准确地说,它很容易在一个系统上重现,使得该系统无法使用,但在相同的输入下难以在其他任何地方重现.
应用程序使用服务包装器作为服务运行.我们确实设法更改配置以启动它,并选择在OOM上输出堆转储文件,但不幸的是,它们被截断,很可能是由于服务包装器超时并在写入文件时终止进程.这很明显,因为最大内存设置为1GB,而hprof文件小到700MB,这对于OOM上的整个堆来说太小了.
需要花费大量资金来进一步配置包装器以使java进程有更长的时间来写出堆,但我们正在使用这两个选项来实现这一点:
wrapper.jvm_exit.timeout=600
wrapper.shutdown.timeout=600
Run Code Online (Sandbox Code Playgroud)
问题是,我能用截断的hprof文件做些什么有用吗?Eclipse MAT扼杀它们.Jhat似乎加载了它们,但随后只显示了3个大小为0的Java.Object实例.我试过YourKit,它无法写出它的oids文件.
在我看来,这些文件应该包含一些有用的,可访问的信息.有没有一个工具可以读取那里有什么?
感谢您的时间!
我有一个程序,随着时间的推移逐渐使用越来越多的内存.我正在使用jmap和jhat来尝试和诊断它,但我仍然不是那里.
该程序是一个长期运行的服务器,由hbase数据存储区支持,为许多其他东西提供thrift服务.但是,运行几天之后,它最终将达到分配的堆限制,并且几乎所有时间都在垃圾收集中来回晃动.似乎引用会被保存到某个地方的大量数据中
在摆弄jstat和jconsole之后,我最终得到了运行进程的jmap的heapdumps,并通过jhat运行它,并且数字简单不会累加到内存利用率附近的任何地方
jmap -F -dump:live,format=b,file=heap.dump 12765
jmap -F -dump:format=b,file=heap.all 12765
直方图顶部的一些东西
Class Instance Count Total Size
class [B 7493 228042570
class java.util.HashMap$Entry 2833152 79328256
class [Ljava.util.HashMap$Entry; 541 33647856
class [Ljava.lang.Object; 303698 29106440
class java.lang.Long 2851889 22815112
class org.apache.hadoop.hbase.KeyValue 303593 13358092
class org.apache.hadoop.hbase.client.Result 303592 9714944
class [I 14074 9146580
class java.util.LinkedList$Entry 303841 7292184
class [Lorg.apache.hadoop.hbase.KeyValue; 303592 7286208
class org.apache.hadoop.hbase.io.ImmutableBytesWritable 305097 4881552
class java.util.ArrayList 302633 4842128
class [Lorg.apache.hadoop.hbase.client.Result; 297 2433488
class [C 5391 320190
Run Code Online (Sandbox Code Playgroud)
虽然这里的总数并没有加起来,但是在进行堆转储时,进程使用了超过1GB的内存.
直接明显的罪魁祸首似乎是我在整个地方留下了HBase Result和KeyValue条目.试图追踪引用,我最终命中了
Object …Run Code Online (Sandbox Code Playgroud) 我有一个java程序,它一直调用java.util.zip压缩/解压缩数据.它会在几秒钟内耗尽内存.我有一个内存转储,jmap我正在查看它jhat.
终结器摘要显示Total instances pending finalization: 0.如果我理解正确,我没有任何对象(1)有finalize()方法,(2)已经被GC标记,(3)等待最终确定.这似乎很好.
当我查看特定对象时,对该对象的唯一引用是a java.lang.ref.Finalizer.无论对象是否为GC,都会为每个具有finalize()方法的对象创建Finalizer对象.所以看起来没有什么能阻止这个Deflater对象被GC控制.
对象位于0x7f4aeb7a35d0
java.util.zip.Deflater@0x7f4aeb7a35d0的实例(51个字节)
对此对象的引用:
java.lang.ref.Finalizer@0x7f4aeb8607c8(64字节):字段指示对象
该程序暂停运行System.in.read().一段时间后内存使用量不会下降.
更新:
我应该说清楚.内存转储显示许多对象没有GC,但没有其他对象(Finalizer对象除外)引用它们.我试图找出他们为什么不是GC的.
我有一个(以前)正在运行的Java进程的堆转储.在转储时,进程挂起与另一台服务器通信.我希望能够重建我的应用程序所做的确切请求.
虽然我的客户端与SOAP Web服务通信,但模型对象恰好是Serializable,所以我想要做的是导出请求对象(Serializable如果可能的话使用它的形式)然后我可以轻松地重新导入该对象(只需反序列化它) )进入测试应用程序.
我的问题是我找不到从堆转储中导出对象的方法.我是能够找到使用有问题的对象OQL,所以我知道它的存在-我只是无法找到提供获取对象了堆转储的任何方式任何工具.
因为我的课程恰好是Serializable我认为最简单的.但是,如果我能以任何其他可解析的格式得到它,我可以以编程方式重建该对象.
想法?
我正在尝试分析从遇到内存问题的 java 进程中获取的堆转储。转储是使用 jmap 获取的。我在转储文件上使用 jhat - 我得到
java.io.IOException: Unrecognized magic number: 169897589
at com.sun.tools.hat.internal.parser.Reader.readFile(Reader.java:94)
at com.sun.tools.hat.Main.main(Main.java:159)
jdk 1.6和1.7都给出相同的错误。我在 Windows 计算机上本地运行 jhat(将转储文件复制到 后),转储文件是在 Linux 服务器上获取的。
有什么想法我做错了吗?
我正在尝试使用jhat / OQL来跟踪Tomcat容器中的内存泄漏。我想问的问题是:
“向我展示可以从javax.servlet.http.HttpSession访问的foo.bar.Cacheable类的所有实例(和子实例)”
我设法提出了以下内容,但这并未显示foo.bar.Cacheable的子类(这很重要,因为这实际上是一个接口)。
select filter(reachables(s), "/foo.bar.Cacheable/(classof(it).name)") from javax.servlet.http.HttpSession s
Run Code Online (Sandbox Code Playgroud)
我尝试了以下概念的各种排列,但始终会出错(未定义“ foo”)。
select filter(reachables(s), classof(it) instanceof foo.bar.Cacheable) from javax.servlet.http.HttpSession s
Run Code Online (Sandbox Code Playgroud)
谁能通过OQL帮我解决我做错的事情吗?
为什么每个对象看起来都标记为新的,而不仅仅是第二个快照中但不在我的基线快照中的对象?在线查看,我看到一些建议,我需要使用hprof而不是jmap来进行内存转储,但似乎hprof以完全相同的格式生成转储.
这是JDK 1.6.0_14; 我试过Windows和UNIX.
我有兴趣知道为什么visualvm OQL在以下语句中有问题:
select filter(heap.objects("java.util.HashMap"), isTrue(it));
function isTrue(object) {
return true;
}
Run Code Online (Sandbox Code Playgroud)
例外情况是:
javax.script.ScriptException: sun.org.mozilla.javascript.internal.EcmaError: ReferenceError: "it" is not defined. (#1)
Run Code Online (Sandbox Code Playgroud)
相比之下,visualvm OQL在以下任何示例中都没有问题:
示例1(注意"它"未引用):
select filter(heap.objects("java.util.HashMap"),
function(it) {
return true;
});
Run Code Online (Sandbox Code Playgroud)
示例2(注意"它"被引用):
select filter(heap.objects("java.util.HashMap"), isTrue("it"));
function isTrue(object) {
if (object instanceof String) {
throw "String passed!";
}
return true;
}
Run Code Online (Sandbox Code Playgroud)
示例3("函数(it)"由于某种原因在OQL中专门处理?):
select filter(heap.objects("java.util.HashMap"), function(it) { return isTrue(it); });
function isTrue(object) {
return true;
}
Run Code Online (Sandbox Code Playgroud)
我问这个是因为它看起来不直观,非直观行为的变化出乎意料地出现,当我试图创造可用的东西时,我放慢了速度.