Jmap堆转储,是否包括年轻一代?

快问

jmap堆转储是仅包含旧代,还是年轻代?


很长的解释

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

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

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

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

因此,这意味着我在GC完成工作后立即进行了第二次转储,这就是为什么它的尺寸更小。 我对吗 ?

附加信息

Java args:

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

快速回答

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

答案很长

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

通常,您的Full GC应该在Old Gen达到99%之前启动.JVM将决定何时运行完整的GC。 你的Young Gen会波动很多,因为这是最快创建/删除对象的地方。 在完整的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  

使用像MAT这样的工具,您将能够看到所有对象,泄漏嫌疑人以及关于代的各种其他统计数据,堆的引用。

编辑调整讨论

根据您的启动参数,您可以尝试一些操作

  • 将-Xms设置为与-Xmx相同的值。 通过这样做,JVM不必花时间分配更多堆。 如果您希望您的应用程序需要4gb,请立即将其全部用完
  • 根据运行此应用程序的系统上的处理器数量,您可以设置-XX:ParallelGCThreads=##的标志-XX:ParallelGCThreads=##
  • 我没有尝试过这个,但是文档显示了-XX:+UseParallelOldGC的参数,它显示了一些减少旧GC集合时间的承诺。
  • 尝试将新一代的大小更改为堆的1/4。 (1024而不是64)这可能会迫使老一代过多。 默认大小约为30%,您的应用程序配置为年轻人使用约2%。 虽然你没有配置最大尺寸,但我担心太多数据会被移到旧版本,因为新版本太小而无法处理所有请求。 因此,您必须执行更多完整(暂停)GC才能清理内存。

我确实相信如果你如此快地分配这么多的内存,那么它可能是一代问题,其中内存过早地分配给老一代。 如果对新的gen大小的调整不起作用,那么您需要通过-Xmx配置添加更多堆,或者后退并找到确切地保留在内存中的内容。 我们之前讨论过的MAT工具可以显示保存在内存中的对象的引用。 我建议先尝试第1点和第4点。 这将是试错,以便您获得正确的值