什么可能导致较小的GC时间和总暂停时间之间的巨大差异?

时间:2010-04-15 15:38:45

标签: java performance garbage-collection jvm

我们有一个对延迟敏感的应用程序,并且正在经历一些我们无法完全理解的与GC相关的暂停。我们偶尔会有一个次要GC导致应用程序暂停时间比报告的GC时间本身长得多。以下是一个示例日志片段:

  

485377.257:[GC 485378.857:[ParNew:105845K-> 621K(118016K),0.0028070秒] 136492K-> 31374K(1035520K), 0.0028720 秒[时间:用户= 0.01 sys = 0.00,实际= 1.61秒]
  应用程序线程停止的总时间: 1.6032830

此处的总暂停时间比报告的GC时间长几个数量级。这些是孤立的和偶然的事件:前一个和后一个次要的GC事件没有显示出这种巨大的差异。

该流程在专用计算机上运行,​​具有大量可用内存,8个内核,运行带有内核2.6.9-89.0.1EL-smp的Red Hat Enterprise Linux ES Release 4 Update 8。我们用(32位)JVM版本1.6.0_13和1.6.0_18观察到了这一点。

我们正在运行这些标志:

  

-server -ea -Xms512m -Xmx512m -XX:+ UseConcMarkSweepGC -XX:NewSize = 128m -XX:MaxNewSize = 128m -XX:+ PrintGCDetails -XX:+ PrintGCTimeStamps -XX:+ PrintGCApplicationStoppedTime -XX:-TraceClassUnloading

有人可以提供一些解释,说明这里可能会发生什么,和/或进一步调查的途径?

3 个答案:

答案 0 :(得分:4)

你是肯定的,你没有交换?通常看到:

时间:用户= 0.01 sys = 0.00,实际= 1.61秒

(来自你的追踪)

表明在这个过程中发生了一些不占用CPU但确实需要挂钟时间的事情......而且这通常是交换或其他I / O.一点点iostat可能有助于揭开光明......

您是否在Java堆外部使用了大量本机内存? (可能通过DirectByteBuffer,nio等等)可能正在吞噬你的“大量免费记忆”声明(令你惊讶的是)。 'top'或vmstat也可能显示这一点。

答案 1 :(得分:2)

“安全时间”是这类事情的一个广泛原因。遗憾的是,GC仅记录从开始工作开始的时间(在所有应用程序线程已在安全点暂停之后)到完成时间(之后线程将从其安全点释放)。 -XX:+ PrintGCApplicationStoppedTime(更准确地说)报告从告诉第一个线程转到安全点到最后一个线程被释放再次运行的时间。

遗憾的是,看到一个线程需要很长时间才能达到一个安全点,并且当发生这种情况时,所有其他好的礼貌线程转到安全点并在被告知时暂停,将等待直到落后者进来。这样的事情的例子是长运行时操作。例如。克隆对象数组在大多数JVM中没有内部安全点机会(想象克隆1GB数组,并且需要在中间进行GC暂停)。您自己的优化计数循环也可以在没有内部安全点的情况下运行很长时间。

[Zing有一个内置的安全时间分析器,部分用于跟踪和击败此类事物]。

答案 2 :(得分:0)

你说有“大量的可用内存”但你的堆大小上限为512MB。您可能会比您想象的更频繁/更早地耗尽内存。