I have the following simple program:
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();
}
}
When I run it using ParallelGC as GC algorithm for young generation:
java -classpath . -XX:InitialHeapSize=4G -XX:MaxHeapSize=4G -XX:NewRatio=3 -XX:+PrintGC -XX:+PrintGCDetails -XX:+UseParallelGC -XX:+UseParallelOldGC GCArrays
the average pause times I get are below 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]
However if I change the line marked with (*) to modify bigArr instead of smallArr the pause time increases to 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]
Note that the program only modifies a single element of the array. However it looks like JVM still scans the whole array to find live objects during minor collection. Is my guess explaining longer GC pauses correct? Why the whole array needs to be scanned when only one element is modified in this case?