我有以下简单的程序:
public class GCArrays {
public static void main(String[] args) {
Object[] bigArr = new Object[1 << 24];
Object[] smallArr = new Object[1 << 12];
bigArr[0x897] = new Object();
smallArr[0x897] = new Object();
for (int i = 0; i < 1e10; i++) {
smallArr[0x897] = new Object(); // (*)
//bigArr[0x897] = new Object();
}
// to prevent bigArr and smallArr from being garbage collected
bigArr[0x897] = new Object();
smallArr[0x897] = new Object();
}
}
当我使用ParallelGC作为GC算法的年轻一代运行它:
java -classpath . -XX:InitialHeapSize=4G -XX:MaxHeapSize=4G -XX:NewRatio=3 -XX:+PrintGC -XX:+PrintGCDetails -XX:+UseParallelGC -XX:+UseParallelOldGC GCArrays
平均暂停时间,我得到低于1ms的:
[GC (Allocation Failure) [PSYoungGen: 1047584K->32K(1048064K)] 1113476K->65924K(4193792K), 0.0007385 secs] [Times: user=0.00 sys=0.00, real=0.00 secs]
但是,如果我改变打上行(*)
修改bigArr
,而不是smallArr
暂停时间增加为10ms:
[GC (Allocation Failure) [PSYoungGen: 1047584K->32K(1048064K)] 1113468K->65916K(4193792K), 0.0101251 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]
请注意,该程序仅修改所述阵列的单个元件。但是它看起来像JVM仍然扫描整个阵列小的收集过程中发现活的对象。是我的猜想解释不再GC暂停正确吗?为什么整个阵列需要当只有一个元件在这种情况下被修改以被扫描?
本文介绍的脏卡片概念以及它们在年轻的GC作用。
在这两种情况下,烧毛旧存储空间的地址为“弄脏”,因此单卡。对于参考阵列对象跨越多个卡(512字节块)只为真改性索引子范围卡被修改。
由于只有单个卡“dirtified”,GC仅需要扫描对应512个字节的存储器。
有了-XX:+UseConcMarkSweepGC
这两个“smallArr”和“bigArr”版本都出现了类似的时机。
-XX:+UseConcMarkSweepGC
+ smallArr
[GC (Allocation Failure) [ParNew: 419458K->2K(471872K), 0.0015320 secs] 485365K->65909K(996160K), 0.0015635 secs]
[Times: user=0.00 sys=0.00, real=0.00 secs]
-XX:+UseConcMarkSweepGC
+ bigArr
[GC (Allocation Failure) [ParNew: 419458K->2K(471872K), 0.0020550 secs] 485365K->65909K(996160K), 0.0020885 secs]
[Times: user=0.00 sys=0.00, real=0.00 secs]
虽然这-XX:+UseParallelOldGC
,似乎GC能够扫描整个“bigArr”
-XX:+ParallelOldGC
+ smallArr
[GC (Allocation Failure) [PSYoungGen: 522768K->16K(523520K)] 588691K->65939K(1047808K), 0.0009430 secs]
[Times: user=0.00 sys=0.00, real=0.00 secs]
-XX:+ParallelOldGC
+ bigArr
[GC (Allocation Failure) [PSYoungGen: 522768K->16K(523008K)] 588687K->65935K(1047296K), 0.0149276 secs]
[Times: user=0.03 sys=0.00, real=0.02 secs]
-XX:+ParallelOldGC
+ bigArr = new Object[1 << 25]
[GC (Allocation Failure) [PSYoungGen: 522768K->16K(523520K)] 654219K->131467K(1047808K), 0.0413473 secs]
[Times: user=0.09 sys=0.00, real=0.04 secs]
反直觉ParallelOldGC
和ConcMarkSweepGC
使用非常相似的年轻GC算法的不同实现。
它看起来像PSYoungGen
缺少优化,只扫描对象数组的脏部分。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句