Java GC 和 Java 堆空间使用的正常行为是什么?



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

一般来说,你的大多数描述都是GC的工作方式。但是,您的具体观察结果,尤其是数字,都不适用于一般情况。

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

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

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

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

  • 所有幸存下来的交换世代对象都将转移到老一代。老一代只会在大部分填满之前进行GC-ed。在您的情况下,每 40 分钟一次。

  • 还有另一个"永久生成",用于加载 jar 目标字节码和资源。

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

您可以尝试使用VisualVM,这将使您动态了解其工作原理。

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

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

有几个JVM选项,它允许你选择生成的大小,GC的类型(GC有几种算法,在java 1.6中默认使用串行GC,例如-XX:-UseConcMarkSweepGC(,GC工作的参数。

你最好试着找到关于世代和不同类型的GC的好文章(算法确实不同,其中一些可以避免世界停止停顿!

是的,很可能。 您可以使用jstat来监控您的 GC,而不是猜测。

我建议你使用内存分析器来确保没有什么简单的你可以做的 ti 提高你产生的垃圾量。

顺便说一句,如果你增加年轻一代的规模,你可以减少有多少垃圾进入终身空间,减少完整收集的频率。 如果你调整得足够多,你可能会发现你每天不到一个完整的收藏。

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

最新更新