为什么GC日志中的某些行只显示堆大小的一个值?

时间:2011-11-01 10:21:08

标签: java garbage-collection diagnostics

我的GC日志中的大多数行看起来像这样:

  

203.558:[GC 326391K-> 324672K(4192192K),0.0452610 secs]

括号中的大小是“提交的堆”,或者(大约)操作系统看到的进程大小。之前的两个数字(“a-> b”)显示GC之前和之后的堆使用情况。

现在,经常,我得到这样的行:

  

42381.926:[GC 10996274K(12565888K),0.0651560 secs]

那些意味着GC没有改变堆使用情况,还是这是一个不同的消息?我查看了Oracle's GC tuning tutorialanother page specifically about GC output,但找不到这种类型的消息。

我正在使用Sun JVM(1.6.0.25),Concurrent Collector(-XX:+UseConcMarkSweepGC),唯一与输出相关的启动选项是-Xloggc:gc.log

3 个答案:

答案 0 :(得分:1)

我在JDK 1.6更新23的源代码中搜索了“secs”(我可以找到最新的1.6版本)和正则表达式“[^”] * - > [^“] *”通过希望找到潜在客户的GC代码文件夹。我还搜索了OpenJDK 1.7代码。然后我尝试在整个HotSpot文件夹中搜索“[^”] * - > [^“] *”?。* secs。然而,我发现的GC记录的唯一一行似乎与您所看到的一致

gclog_or_tty->print("[%s-concurrent-%s: %3.3f/%3.3f secs]",
             _collector->cmsGen()->short_name(),
             _phase, _collector->timerValue(), _wallclock.seconds());

这是在concurrentMarkSweepGeneration.cpp中。它看起来与您看到的格式不太接近。要么我没有很好地搜索,要么在更新23和更新25之间有关GC记录的更改。

如果有人更清楚地知道在哪里寻找或搜索什么,我很乐意帮忙。

编辑:等一下,从concurrentMarkSweepGeneration.cpp的第827行开始找到一些东西:

void ConcurrentMarkSweepGeneration::printOccupancy(const char *s) {
  GenCollectedHeap* gch = GenCollectedHeap::heap();
  if (PrintGCDetails) {
    if (Verbose) {
      gclog_or_tty->print(" [%d %s-%s: "SIZE_FORMAT"("SIZE_FORMAT")]",
        level(), short_name(), s, used(), capacity());
    } else {
      gclog_or_tty->print(" [%d %s-%s: "SIZE_FORMAT"K("SIZE_FORMAT"K)]",
        level(), short_name(), s, used() / K, capacity() / K);
    }
  }
  if (Verbose) {
    gclog_or_tty->print(" "SIZE_FORMAT"("SIZE_FORMAT")",
              gch->used(), gch->capacity());
  } else {
    gclog_or_tty->print(" "SIZE_FORMAT"K("SIZE_FORMAT"K)",
              gch->used() / K, gch->capacity() / K);
  }
}

这个函数只在这里被调用:

void CMSCollector::do_CMS_operation(CMS_op_type op) {
  gclog_or_tty->date_stamp(PrintGC && PrintGCDateStamps);
  TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
  TraceTime t("GC", PrintGC, !PrintGCDetails, gclog_or_tty);
  TraceCollectorStats tcs(counters());

  switch (op) {
    case CMS_op_checkpointRootsInitial: {
      checkpointRootsInitial(true);       // asynch
      if (PrintGC) {
        _cmsGen->printOccupancy("initial-mark");
      }
      break;
    }
    case CMS_op_checkpointRootsFinal: {
      checkpointRootsFinal(true,    // asynch
                           false,   // !clear_all_soft_refs
                           false);  // !init_mark_was_synchronous
      if (PrintGC) {
        _cmsGen->printOccupancy("remark");
      }
      break;
    }
    default:
      fatal("No such CMS_op");
  }
}

这看起来很像你得到的。我不太擅长解释这段代码,但我会说你所看到的只是一条日志行,显示当前堆使用后跟括号中的已提交堆大小,仅此而已。基本上相同的信息,但垃圾收集前没有使用。

答案 1 :(得分:0)

你能列出所有gc-looging相关的jvm参数吗?

查看您的输出我不认为您正在使用

-verbose:GC -XX:+ PrintGCTimeStamps -XX:+ PrintGCDetails

另请检查

Explanation of Tomcat GC log statements

Java Garbage Collection Log messages

答案 2 :(得分:0)

我认为这一行是由timer.cpp中的TraceTime启动的,它是从CMS(concurrentMarkSweepGeneration.cpp do_CMS_operation)和ParNew(parNewGeneration.cpp collect)调用的。这段代码似乎是源代码

void ConcurrentMarkSweepGeneration::printOccupancy(const char *s) {
    GenCollectedHeap* gch = GenCollectedHeap::heap();
    if (PrintGCDetails) {
      if (Verbose) {
        gclog_or_tty->print(" [%d %s-%s: "SIZE_FORMAT"("SIZE_FORMAT")]",
          level(), short_name(), s, used(), capacity());
    } else {
        gclog_or_tty->print(" [%d %s-%s: "SIZE_FORMAT"K("SIZE_FORMAT"K)]",
          level(), short_name(), s, used() / K, capacity() / K);
      }
    }
    if (Verbose) {
      gclog_or_tty->print(" "SIZE_FORMAT"("SIZE_FORMAT")",
                gch->used(), gch->capacity());
    } else {
      gclog_or_tty->print(" "SIZE_FORMAT"K("SIZE_FORMAT"K)",
              gch->used() / K, gch->capacity() / K);
    }
}

因此,这是堆的总占用率(所有代的总和)以及当前GC操作期间经过的时间的陈述。打印时间似乎是作为计时器的挂起时间(os::elapsed_counter因此,例如在Linux上为gettimeofday)在TraceTime被实例化并且在销毁时停止/打印时启动。

如果您愿意,我建议您添加verbose:gc以获取更多信息。