5

快速提问

jmap 堆转储是否只包括老一代,还是包括年轻一代?


长解释

我有 2 个堆转储(jmap -heap:format=b 9999):

  • 我的一台无负载服务器(无 HTTP 请求)
  • 一个同时工作 50% CPU,高负载(基准测试)

现在,第一个转储显示的堆大小比第二个大(我认为这很奇怪)。

这可能是因为垃圾收集器经常运行(是的,JVM 几乎满了),年轻一代(高负载)经常变化吗?老一代已满 99%,我注意到年轻一代的空间使用情况变化很大。

所以这意味着我在 GC 完成他的工作后立即进行了第二次转储,这就是它的大小更小的原因。我对吗 ?

附加信息

Java 参数:

-XX:+UseParallelGC -XX:+AggressiveHeap
-Xms2048m -Xmx4096m -XX:NewSize=64m
-XX:PermSize=64m -XX:MaxPermSize=512m
4

1 回答 1

10

快速回答

两者 - 堆由年轻代和老年代组成。因此,当您进行堆转储时,内容包含两者。堆转储的统计信息应该分开。尝试删除命令的二进制部分并以纯文本形式查看。您将看到您的配置摘要,然后是每一代的细分。另一方面,-histo 只会显示堆上的所有对象,没有区别

长答案

可能是第二个进程的垃圾收集刚刚完成。或者相反,第一个进程可能有一段时间没有完整的收集,并且处于更高的内存中。当您进行捕获时,此应用程序/服务器是否刚刚重新启动?如果您使用类似的工具查看空闲进程jvisualvm,您会看到内存分配图上下移动,即使您的进程没有做任何工作。这只是 JVM 在做自己的事情。

通常,您的 Full GC 应该在老一代中达到 99% 之前就开始了。JVM 将决定何时运行 Full GC。你的年轻一代会波动很大,因为这是创建/删除对象最快的地方。在运行完整 GC 之前,将执行许多部分 GC 以清除年轻代。两者之间的差异将意味着您的 JVM 活动暂停。看到部分 GC 不会损害您的应用程序。但是完整 GC 的暂停时间会在您的应用程序运行时停止它。因此,您将希望尽可能减少这些。

如果您正在寻找内存泄漏或只是分析以查看您的应用程序 gc 是如何工作的,我建议您使用启动标志来打印垃圾收集统计信息。

-XX:+PrintGCDetails -verbose:gc -Xloggc:/log/path/gc.log

运行您的程序一段时间,然后将捕获的日志加载到工具中以帮助可视化结果。我个人使用IBM Support Assistant Workbench 中提供的垃圾收集和内存可视化工具。它将为您提供捕获的垃圾收集统计信息的摘要以及一个动态图表,您可以使用它来查看应用程序中的内存的行为方式。这不会告诉你堆上有什么对象。

在您的应用程序出现问题时,如果您可以暂停一下,我会修改您的 jmap 命令以执行以下操作

jmap -dump:format=b,file=/file/location/dump.hprof <pid>

使用MAT之类的工具,您将能够查看所有对象、泄漏嫌疑人以及有关堆的世代、引用的各种其他统计信息。

编辑调整讨论

根据您的启动参数,您可以尝试一些事情

  • 将 -Xms 设置为与 -Xmx 相同的值。通过这样做,JVM 不必花时间分配更多的堆。如果您希望您的应用程序占用 4gb,请立即提供
  • 根据您正在运行此应用程序的系统上的处理器数量,您可以为 -XX:ParallelGCThreads=##.
  • 我没有尝试过这个,但文档显示了一个参数, -XX:+UseParallelOldGC该参数显示了一些减少旧 GC 收集时间的承诺。
  • 尝试将您的新一代大小更改为堆的 1/4。(1024 而不是 64)这可能对老一代造成了太大的压力。默认大小约为 30%,您已将应用程序配置为年轻一代使用约 2%。尽管您没有配置最大大小,但我担心太多数据会被移动到旧代,因为新代太小而无法处理所有请求。因此,您必须执行更完整(暂停)的 GC 才能清理内存。

总的来说,我确实相信,如果您如此快速地分配这么多内存,那么可能是内存被过早分配给老一代的一代问题。如果对新代大小的调整不起作用,那么您需要通过 -Xmx 配置添加更多堆,或者退后一步,准确找到内存中的内容。我们之前讨论过的 MAT 工具可以向您展示持有内存中对象的引用。我建议先尝试第 1 点和第 4 点。这将是您获得正确值的反复试验

于 2011-05-19T12:49:00.130 回答