Java垃圾回收日志消息

99

我已经配置了Java将垃圾回收信息输出到日志中(详细GC)。我不确定日志中的垃圾回收条目的含义。以下是这些条目的示例。我在Google上搜索过,但没有找到可靠的解释。

我有一些合理的猜测,但我正在寻找提供严格定义条目中数字含义的答案,并由可靠来源支持。引用Sun文档的所有答案自动+1。我的问题是:

  1. PSYoungGen是什么意思?我认为它与之前(年轻?)的一代有关,但具体是什么?
  2. 第二个三元组和第一个有什么区别?
  3. 为什么第一个三元组指定了名称(PSYoungGen),而第二个没有?
  4. 每个三元组中的每个数字(内存大小)是什么意思。例如,在109884K->14201K(139904K)中,GC前的内存是109884k,然后被减少到14201K。第三个数字有什么作用?为什么我们需要第二组数字?

8109.128:[GC [PSYoungGen:109884K->14201K(139904K)] 691015K->595332K(1119040K),0.0454530 secs]

8112.111:[GC [PSYoungGen:126649K->15528K(142336K)] 707780K->605892K(1121472K),0.0934560 secs]

8112.802:[GC [PSYoungGen:130344K->3732K(118592K)] 720708K->607895K(1097728K),0.0682690 secs]


整个堆,堆的年轻代部分,minor gc(即新生代垃圾回收)是垃圾回收的一种方式。请参考 http://www.cubrid.org/blog/dev-platform/understanding-java-garbage-collection/。 - MarianP
3个回答

129
  1. PSYoungGen指的是用于小型垃圾收集(minor collection)的垃圾回收器。PS代表Parallel Scavenge。
  2. 第一组数字是年轻代的内存使用情况,前一个数字为GC前的大小,后一个数字为GC后的大小;第二组数字是整个堆的内存使用情况。(Diagnosing a Garbage Collection problem详细说明了格式)
  3. 名称指示了相关代和垃圾回收器,第二组数字是整个堆的内存使用情况。

一个关联的full GC例子也展示了用于老年代和永久代的垃圾收集器:

3.757: [Full GC [PSYoungGen: 2672K->0K(35584K)] 
            [ParOldGen: 3225K->5735K(43712K)] 5898K->5735K(79296K) 
            [PSPermGen: 13533K->13516K(27584K)], 0.0860402 secs]

最后,让我们一行一行地分析您示例中的日志输出:

8109.128: [GC [PSYoungGen: 109884K->14201K(139904K)] 691015K->595332K(1119040K), 0.0454530 secs]
  • GC前已使用107Mb内存GC后使用14Mb内存,年轻代最大容量为137Mb
  • GC前堆已使用675Mb内存GC后堆已使用581Mb内存,最大堆容量为1Gb
  • 距离JVM启动已经8109.128秒,发生了一次Minor GC,耗时0.04秒

9
仅作一小点评论,括号内的数值并不是最大尺寸,永远都不是,它只是目前的最大尺寸。如果垃圾回收无法释放堆空间,使其低于此限制,则操作系统需要更多的空间,并且该值将增加。当然要遵守-Xmx定义的限制。 - rafa.ferreira
1
@rafa.ferreira 我认为括号中的值,即1119040K是已分配堆大小。我不认为GC在任何地方打印“最大堆”大小。参考1参考2 - rohitmohta

91

大部分内容在GC调优指南中有详细解释(无论如何您都应该阅读这些内容)。

命令行选项-verbose:gc会导致有关堆和垃圾回收的信息在每次回收时打印出来。例如,下面是来自大型服务器应用程序的输出:

[GC 325407K->83000K(776768K), 0.2300771 secs]
[GC 325816K->83372K(776768K), 0.2454258 secs]
[Full GC 267628K->83769K(776768K), 1.8479984 secs]
这里我们看到两次小型垃圾回收后跟着一次大型垃圾回收。箭头前后的数字(例如第一行的325407K->83000K)分别表示垃圾回收前后存活对象的总大小。在小型垃圾回收之后,大小包括一些垃圾对象(不再存活),但不能被回收利用。这些对象要么包含在旧生代中,要么是从旧生代或永久代引用过来的。

括号中的下一个数字(例如第一行再次出现的(776768K))是堆的承诺大小:可用于Java对象而无需从操作系统请求更多内存的空间量。请注意,此数字不包括其中一个survivor space,因为在任何给定时间只能使用一个,并且也不包括持有虚拟机使用的元数据的永久代。

行中的最后一项(例如0.2300771秒)表示执行垃圾回收所花费的时间;在这种情况下约为四分之一秒。

第三行的大型垃圾回收格式类似。

-verbose:gc输出的格式可能会在以后的版本中发生变化。

我不确定为什么你的输出中有PSYoungGen; 你改变过垃圾收集器吗?


在哪里可以找到GC日志文件? - Mr Lou
7
这个回答并没有真正回答原问题。我认为michaeljoseph的回答更好。它回答了Ethan提出的问题,并更好地分解了原始示例。虽然在他的回答中存在两个问题(他的链接现在已经失效,而rafa.ferreria指出了另一个问题),但它并不只是重复Oracle文档。 - Dirk

24

我只想提一下,人们可以使用

-XX:+PrintGCDetails

选项来获得详细的垃圾回收日志。

-XX:+PrintGCDetails 

如果你设置了-XX:+PrintGCDetails参数,那么你会看到类似答案中所示的PSYoungGen或PSPermGen输出信息。

此外,-Xloggc:gc.log似乎生成与-verbose:gc相同的输出,但你可以在前者中指定一个输出文件。

使用示例:

java -Xloggc:./memory.log -XX:+PrintGCDetails Memory
为了更好地可视化数据,您可以尝试使用gcviewer(在GitHub上可以找到更新版本)。
注意正确编写参数,我忘记加上“+”,导致我的 JBoss 无法启动,也没有任何错误消息!

3
请注意,在Java重新启动时(例如,如果您因内存问题重新启动Tomcat,并且希望查看gc.log文件),gc.log文件将被覆盖。或者至少在旋转GC日志时会被覆盖。还有许多其他选项可控制GC记录。请参见http://www.oracle.com/technetwork/articles/java/vmoptions-jsp-140102.html。特别是要考虑使用 -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=<一些文件数> -XX:GCLogFileSize=<一些大小> -XX:+PrintTenuringDistribution - Dan Pritts

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接