First of all, you are specifying -XX:SurvivorRatio=8
, but -XX:+UseAdaptiveSizePolicy
is on, as such SurvivorRatio
is simply ignored.
Then, I have explained what some of the lines you see a bit in this answer.
Anyway, I ran this with java-13
and Unified Logging, specifically with:
"-Xlog:heap*=debug" "-Xlog:gc*=debug"
to see what is going on.
From the logs, I see that there are only two GC cycles, as part of this code. Actually it's just one, a concurrent cycle, but as part of that cycle, young GC is triggered also. Logically, I treat that as a single GC cycle, but GC logs reports as two.
As such your logs will contain:
[0.127s][debug][gc,ergo] Request concurrent cycle initiation (requested by GC cause). GC cause: G1 Humongous Allocation
And also, you will have:
[0.133s][info ][gc ] GC(0) Pause Young (Concurrent Start) (G1 Humongous Allocation) 7M->6M(20M) 5.753ms
[0.133s][info ][gc,cpu] GC(0) User=0.01s Sys=0.00s Real=0.01s
[0.133s][info ][gc ] GC(1) Concurrent Cycle
Notice how the concurrent cycle is piggy-backed off the young cycle.
Now, to answer about the regions.
The GC (0)
starts with:
[0.127s][debug][gc,heap] GC(0) Heap before GC invocations=0 (full 0)...
[0.127s][debug][gc,heap] GC(0) region size 1024K, 1 young, 0 survivors
So you start with 1 Young = 1 Eden + 0 Survivors
Later, there will be a log:
[0.133s][info ][gc,heap] GC(0) Eden regions: 1 -> 0 (9)
[0.133s][info ][gc,heap] GC(0) Survivor regions: 0 -> 1 (2)
As I have explained in the link I gave above, the next cycle of young GC will be hinted to use:
11 young regions = 9 Eden + 2 Survivor
But, as I said there, this is only a hint. Since this is a humongous allocation, it will actually use less regions as seen by the heap layout when you exit:
[0.157s][info ][gc,heap,exit] garbage-first heap total 20480K....
[0.158s][info ][gc,heap,exit] region size 1024K, 2 young 1 survivors
The GC has no idea that you only allocate big Objects and it should not use any young regions at all and its heuristics still tell to create some young regions. That is why you see those 2 young, 1 survivor
.
But, if you run your code long enough:
public static void main(String[] args) {
while (true) {
invokeMe();
}
}
public static int invokeMe() {
int x = 1024;
int factor = 2;
byte[] allocation1 = new byte[factor * x * x];
allocation1[2] = 3;
byte[] allocation2 = new byte[factor * x * x];
byte[] allocation3 = new byte[factor * x * x];
byte[] allocation4 = new byte[factor * factor * x * x];
return Arrays.hashCode(allocation1) ^ Arrays.hashCode(allocation2)
^ Arrays.hashCode(allocation3) ^ Arrays.hashCode(allocation4);
}
You will start seeing entries like:
[0.521s][debug][gc,heap] GC(62) Heap before GC invocations=62
[0.521s][debug][gc,heap] GC(62) region size 1024K, 0 young (0K), 0 survivors (0K)
Notice the 0 young, 0 survivor
.