了解 Java 堆转储

发布于 2024-11-25 04:15:02 字数 2138 浏览 3 评论 0原文

我已经尝试在我的应用程序中查找内存泄漏一周了,但没有成功。我尝试进行堆转储并使用 jhat 查看转储并追踪内存泄漏。

这是最好的方法吗?使用堆转储追踪内存泄漏的最佳方法是什么?

感谢您的帮助。

使用的虚拟机: java 版本“1.6.0_25” Java(TM) SE 运行时环境(版本 1.6.0_25-b06) Java HotSpot(TM) 64 位服务器 VM(版本 20.0-b11,混合模式)

JVM 选项: -Xmx1600m -XX:+UseParallelGC -XX:MaxPermSize=256m -Xms1600m -XX:+HeapDumpOnOutOfMemoryError - XX:+PrintGCDetails -XX:+PrintGCTimeStamps -verbose:gc -Xloggc:/tmp/gc.log

OOME 堆栈跟踪: 无法获取此信息。内核因内存不足错误而终止了该进程。

GC日志:最后几行

48587.245: [GC [PSYoungGen: 407168K->37504K(476160K)] 506729K->137065K(1568448K), 3.0673560 secs] [Times: user=3.53 sys=0.00, real=3.07 secs] 
50318.617: [GC [PSYoungGen: 444224K->37536K(476416K)] 543785K->175177K(1568704K), 3.6635990 secs] [Times: user=3.70 sys=0.00, real=3.67 secs] 
50453.841: [GC [PSYoungGen: 70092K->2912K(476672K)] 207734K->178513K(1568960K), 1.0164250 secs] [Times: user=1.29 sys=0.00, real=1.02 secs] 
50454.858: [Full GC (System) [PSYoungGen: 2912K->0K(476672K)] [PSOldGen: 175601K->137776K(1092288K)] 178513K->137776K(1568960K) [PSPermGen: 60627K->60627K(74368K)], 2.0082140 secs] [Times: user=2.09 sys=0.00, real=2.01 secs] 
52186.496: [GC [PSYoungGen: 407104K->37312K(444416K)] 544880K->175088K(1536704K), 3.3705440 secs] [Times: user=3.93 sys=0.00, real=3.37 secs] 
53919.975: [GC [PSYoungGen: 444416K->37536K(476608K)] 582192K->213032K(1568896K), 3.4242980 secs] [Times: user=4.09 sys=0.00, real=3.42 secs] 
54056.872: [GC [PSYoungGen: 70113K->2880K(476480K)] 245609K->216320K(1568768K), 0.9691980 secs] [Times: user=1.19 sys=0.00, real=0.97 secs] 
54057.842: [Full GC (System) [PSYoungGen: 2880K->0K(476480K)] [PSOldGen: 213440K->99561K(1092288K)] 216320K->99561K(1568768K) [PSPermGen: 60628K->60628K(72320K)], 2.2203320 secs] [Times: user=2.23 sys=0.01, real=2.22 secs] 
55796.688: [GC [PSYoungGen: 406976K->37504K(476160K)] 506537K->137065K(1568448K), 3.2680080 secs]

更新:检查内核日志消息后,发现它是一个oom-killer。但为什么系统会杀死该进程,不是因为该进程占用了大量的系统资源(内存)。

I have been trying to find memory leak in my application for a week now without any success. I tried to do a heap dump and use jhat to look at the dump and trace down the memory leak.

Is this a best approach? Whats the best way to track down the memory leak with the heap dump.

Appreciate your help.

VM used : java version "1.6.0_25"
Java(TM) SE Runtime Environment (build 1.6.0_25-b06)
Java HotSpot(TM) 64-Bit Server VM (build 20.0-b11, mixed mode)

JVM Options : -Xmx1600m -XX:+UseParallelGC -XX:MaxPermSize=256m -Xms1600m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -verbose:gc -Xloggc:/tmp/gc.log

OOME Stack trace: Couldn't get this. The kernel killed the process with out of memory error.

GC Log : The last few lines

48587.245: [GC [PSYoungGen: 407168K->37504K(476160K)] 506729K->137065K(1568448K), 3.0673560 secs] [Times: user=3.53 sys=0.00, real=3.07 secs] 
50318.617: [GC [PSYoungGen: 444224K->37536K(476416K)] 543785K->175177K(1568704K), 3.6635990 secs] [Times: user=3.70 sys=0.00, real=3.67 secs] 
50453.841: [GC [PSYoungGen: 70092K->2912K(476672K)] 207734K->178513K(1568960K), 1.0164250 secs] [Times: user=1.29 sys=0.00, real=1.02 secs] 
50454.858: [Full GC (System) [PSYoungGen: 2912K->0K(476672K)] [PSOldGen: 175601K->137776K(1092288K)] 178513K->137776K(1568960K) [PSPermGen: 60627K->60627K(74368K)], 2.0082140 secs] [Times: user=2.09 sys=0.00, real=2.01 secs] 
52186.496: [GC [PSYoungGen: 407104K->37312K(444416K)] 544880K->175088K(1536704K), 3.3705440 secs] [Times: user=3.93 sys=0.00, real=3.37 secs] 
53919.975: [GC [PSYoungGen: 444416K->37536K(476608K)] 582192K->213032K(1568896K), 3.4242980 secs] [Times: user=4.09 sys=0.00, real=3.42 secs] 
54056.872: [GC [PSYoungGen: 70113K->2880K(476480K)] 245609K->216320K(1568768K), 0.9691980 secs] [Times: user=1.19 sys=0.00, real=0.97 secs] 
54057.842: [Full GC (System) [PSYoungGen: 2880K->0K(476480K)] [PSOldGen: 213440K->99561K(1092288K)] 216320K->99561K(1568768K) [PSPermGen: 60628K->60628K(72320K)], 2.2203320 secs] [Times: user=2.23 sys=0.01, real=2.22 secs] 
55796.688: [GC [PSYoungGen: 406976K->37504K(476160K)] 506537K->137065K(1568448K), 3.2680080 secs]

Update: Upon checking the kernel log messages, its a oom-killer. But still why is the system killing the process, isn't it because the process eating up lot of system resources ( memory ).

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

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

发布评论

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

评论(3

白鸥掠海 2024-12-02 04:15:02

关于java内存泄漏的问题与这个重复,

href="https://stackoverflow.com/questions/2064427/recommendations-for-a-heap-analysis-tool-for-java">那个,等等。不过,这里 采取一些堆快照,如上面链接的答案中所述。

然后,如果您很了解整个应用程序,您可以观察实例计数并找出哪种类型有太多实例。例如,如果您知道某个类是单例,但您在内存中看到该类的 100 个实例,那么这肯定表明那里正在发生一些有趣的事情。或者,您可以比较快照以找出哪些类型的对象数量随着时间的推移而增长;这里的关键是您正在寻找在某个使用期间的相对增长。

一旦知道泄漏的内容,您就可以回溯引用以找到无法收集的根引用。

最后,请记住,您看到 OutOfMemoryError 可能不是因为内存泄漏,而是因为堆的某些部分对于应用程序来说太小。要检查是否属于这种情况:

  • 请在问题中包含您正在使用的虚拟机类型。
  • 在您的问题中包含启动 java 时传递的参数。您的最小、最大和永久堆大小是多少?您使用什么类型的垃圾收集器?
  • 在您的问题中包含 OOME 堆栈跟踪,以防其中有一些有用的信息。
  • 打开详细 GC 日志记录,以便您可以看到堆的哪些部分正在增长。
  • 打开 HeapDumpOnOutOfMemoryError 参数,以便获得堆当进程终止时在最后转储。

更新:我不确定最新更新中的“内核因内存不足错误而终止了进程”是什么意思,但我认为您可能会说 linux 内存不足杀手被调用。是这样的吗?这个问题与 java OutOfMemoryError 完全不同。有关所发生情况的更多详细信息,请查看我刚刚链接到的页面中的链接,包括那个。但问题的解决方案很简单:在有问题的服务器上使用更少的内存。我想您可以删除相关 java 进程的最小和最大堆大小,但您需要确保不会触发真正的 java OutOfMemoryErrors。您可以将一些流程移到其他地方吗?您能否将内存杀手与特定进程的启动关联起来?

The question about java memory leaks is a duplicate of this, that, etc. Still, here are a few thoughts:

Start by taking a few heap snapshots as described in the answer linked above.

Then, if you know the whole application well, you can eyeball the instance counts and find which type has too many instances sticking around. For example, if you know that a class is a singleton, yet you see 100 instances of that class in memory, then that's a sure sign that something funny is going on there. Alternatively you can compare the snapshots to find which types of objects are growing in number over time; the key here is that you're looking for relative growth over some usage period.

Once you know what's leaking, you trace back through the references to find the root reference that cannot be collected.

Finally, remember that it's possible that you see an OutOfMemoryError not because you're leaking memory, but rather because some part of your heap is too small for the application. To check whether this is the case:

  • Include in your question the type of VM that you're using.
  • Include in your question the arguments that you pass when starting java. What are your min, max, and permgen heap sizes? What type of garbage collector are you using?
  • Include in your question the OOME stack trace, in case there's some useful information there.
  • Turn on verbose GC logging, so that you can see which part(s) of the heap are growing.
  • Turn on the HeapDumpOnOutOfMemoryError parameter, so that you get a heap dump at the very end when the process dies.

Update: I'm not sure what "kernel killed the process with out of memory error" in your latest update means, but I think you might be saying that the linux out of memory killer was invoked. Was this the case? This problem is completely separate from a java OutOfMemoryError. For more details about what's happening, take a look at the links from the page I just linked to, including this and that. But the solution to your problem is simple: use less memory on the server in question. I suppose that you could drop the min and max heap size of the java process in question, but you need to be sure that you won't trigger real java OutOfMemoryErrors. Can you move some processes elsewhere? Can you correlate the memory killer with the start up of a specific process?

土豪 2024-12-02 04:15:02

内存泄漏可以通过下面提到的 3 个简单步骤来解决:

时捕获堆转储

步骤 1: 在早期启动应用程序 。让它占用实际流量 10 分钟。此时捕获堆转储。堆转储基本上是内存的快照。它包含驻留在内存中的所有对象、存储在这些对象中的值、入站和返回值。这些对象的出站引用。您可以使用以下命令捕获堆转储:

   jmap -dump:format=b,file=<file-path> <pid> 

   where

   pid: is the Java Process Id, whose heap dump should be captured
   file-path: is the file path where heap dump will be written in to.

如果您不想使用 jmap 捕获堆转储,这里还有其他几个选项 捕获堆转储

第 2 步: 在应用程序崩溃之前捕获堆转储

执行第 1 步后,让应用程序运行。在应用程序崩溃之前,再次进行另一个堆转储。通常,在崩溃之前捕获堆转储可能具有挑战性,因为我们不知道应用程序何时会崩溃。是30分钟后、3小时后、还是3天后?因此,最好使用以下 JVM 属性启动应用程序:

    -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=<file-path>

    file-path: is the file path where heap dump will be written in to.

当应用程序遇到 OutOfMemoryError 时,此属性将触发堆转储。

第 3 步: 分析堆转储

导致内存泄漏的对象在此期间不断增长。如果您可以识别在步骤 #1 和步骤 #2 中捕获的堆转储之间大小已增长的对象,那么这些对象就是导致内存泄漏的对象。

您可以考虑使用堆转储分析工具,例如 HeapHero.ioEclipse MAT 用于此目的。当您将堆转储加载到任何工具时,都会有一个部分报告内存中最大的对象。比较步骤 #1 和步骤 #2 中捕获的堆转储的本节内容。如果您发现对象有任何异常增长,那么它们就是导致应用程序中内存泄漏的对象。

Memory leaks can be solved by following below mentioned 3 simple steps:

Step 1: Capture heap dump during early stage

Start your application. Let it take real traffic for 10 minutes. At this point capture heap dump. Heap Dump is basically snapshot of your memory. It contains all objects that are residing in the memory, values stored in those objects, inbound & outbound references of those object. You can capture Heap dump can be captured using following command:

   jmap -dump:format=b,file=<file-path> <pid> 

   where

   pid: is the Java Process Id, whose heap dump should be captured
   file-path: is the file path where heap dump will be written in to.

If you don't want to use jmap for capturing heap dumps, here are several other options to capture heap dumps.

Step 2: Capture heap dump before application crashes

After doing step #1, let the application run. Before application crashes take another heap dump once again. Often times it might be challenging to capture heap dumps before it crashes, because we don't know when application will crash. Is it after 30 minutes, 3 hours, 3 days? Thus, it's ideal to start your application with following JVM property:

    -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=<file-path>

    file-path: is the file path where heap dump will be written in to.

This property will trigger heap dump right when application experiences OutOfMemoryError.

Step 3: Analyze heap dumps

Objects which are causing memory leaks grow over the period. If you can the identify objects whose size has grown between the heap dumps captured in step #1 and step #2, then those are the objects which is causing memory leak.

You can consider using heap dump analyzer tool such as HeapHero.io , Eclipse MAT for this purpose. When you load the heap dumps in to any of the tool, there will be a section reporting largest objects in the memory. Compare this section between heap dump captured in step #1 and step #2. If you notice any abnormal growth of objects, then they are the ones which is causing memory leak in your application.

榕城若虚 2024-12-02 04:15:02

我建议您查看我关于此主题的原始文章。 Java 堆转储分析一开始可能很复杂,但使用诸如 Eclipse Memory Analyzer 简化了该过程。

JVM 堆转储对于以下场景非常有用:

  • 识别 Java 级别的内存泄漏。
  • 识别 Java 级类加载器泄漏。
  • 了解有关特定负载/流量场景下 Java 应用程序内存占用的更多信息。

参考: Java 堆转储:是你能胜任这项任务吗?

I recommend that you review my original article on this subject. Java heap dump analysis can be complex at first but using tools such as Eclipse Memory Analyzer simplifies the process.

JVM Heap Dump's are useful for the following scenarios:

  • Identification of a Java-level memory leak.
  • Identification of a Java-level class loader leak.
  • To learn more about your Java application memory footprint under a certain load/traffic scenario.

Reference: Java heap dump: are you up to the task?

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