2

我不确定是否有一个通用的答案,但我想知道正常的 Java GC 模式和 Java 堆空间使用情况是什么样的。我正在使用 JMeter 测试我的 Java 1.6 应用程序。我正在收集 JMX GC 日志并使用 JMeter JMX GC 和内存插件扩展来绘制它们。GC 模式看起来相当稳定,大多数 GC 操作为 30-40ms,偶尔为 90ms。内存消耗呈锯齿状。JHS 使用量不断向上增长,例如增加到 3GB,并且每 40 分钟内存使用量会自由落体下降到 1GB 左右。然而,最大最小增量会增长,因此锯齿高度会不断增长。它是否每 40 分钟执行一次完整的 GC?

4

3 回答 3

1

一般来说,您的大多数描述都是 GC 的工作原理。但是,您的任何具体观察,尤其是数字,都不适用于一般情况。

首先,每个 JVM 都有一个或多个 GC 实现,您可以选择使用哪一个。以应用最多的SUN JVM(我喜欢这样称呼)和常见的服务器GC模式为例。

首先,内存被划分为 4 个区域。

  • 持有所有最近创建的对象的年轻一代。当这一代已满时,GC 会通过停止您的程序的工作来进行一次停止世界的收集,执行黑白算法并获取过时的对象并将其删除。所以这是你的 30-40 毫秒。

  • 如果一个对象在年轻代中存活了几轮 GC,它将被移入交换代。交换代将对象保留到另一个 GC 数量 - 然后将它们移动到老一代。有 2 个交换代,它们做了双重缓冲,以促进年轻一代更快地工作。如果年轻代将东西转储到交换代并发现交换代大部分已满,则交换代上将发生 GC 并可能将幸存的对象移动到旧代。这很可能使您的 90 毫秒,尽管我不是 100% 确定交换生成是如何工作的。如果我错了,有人纠正我。

  • 所有在 swap gen 中幸存的对象都会被移到老年代。老一代只会被 GC-ed 直到它几乎满了。在您的情况下,每 40 分钟一次。

  • 还有另一个“永久代”用于加载您的 jar 目标字节码和资源。

所有区域的大小都可以通过 JVM 参数进行调整。

您可以尝试使用 VisualVM,它可以让您动态了解它的工作原理。

PS 并非所有 JVM / GC 都以相同的方式工作。如果您使用 G1 收集器或 JRocket,情况可能会略有不同,但总体思路是成立的。

于 2013-10-02T11:57:10.607 回答
0

Java GC 根据对象的生成来工作。有年轻的、终身的和永久的一代。在您的情况下似乎是:每 30-40 毫秒 GC 只处理年轻一代(并将幸存的对象转移到终身代)。它每 40 分钟执行一次完整收集(它会导致世界停止)。注意:它不是按时间发生的,而是按已用内存的百分比发生的。

JVM 有几个选项,可以选择生成的大小,GC 的类型(GC 有几种算法,在 java 1.6 中默认使用 Serial GC,例如-XX:-UseConcMarkSweepGC),GC 工作的参数。

您最好尝试找到有关世代和不同类型 GC 的好文章(算法确实不同,其中一些可以完全避免 stop-the-world 暂停!)

于 2013-10-02T11:50:25.977 回答
0

是的,很可能。无需猜测,您可以使用它jstat来监控您的 GC。

我建议您使用内存分析器来确保您可以做任何简单的事情来提高您产生的垃圾量。

顺便说一句,如果你增加年轻代的大小,你可以减少进入永久空间的垃圾量,从而降低完全收集的频率。如果您对它进行足够的调整,您可能会发现每天不到一个完整的集合。

对于更极端的情况,我已将交易系统调整为每天少于一个集合(次要或主要)

于 2013-10-02T11:43:06.387 回答