Four ways objects enter the old age

  • After minor GC, survivor space cannot hold all surviving objects
  • The age threshold of a viable object has been reached. Procedure Such as 15
  • The big object
  • Dynamic age judgment

Dynamic age judgment

First of all, what is dynamic age judgment?

The book explains:

To sum up: that is to say, if the size of all objects of the same age occupies more than half of the survivor space in the survivor area, objects older than or equal to this age can directly enter the old age.

That’s what the books say.

But that’s not true.

The correct statement is: in a survivor zone, the sum of all age objects in a survivor zone is greater than half of the survivor space, and any object older than or equal to that age can enter the old age.

Let’s go straight to the code and JVM configuration parameters:

JVM configuration parameters:

-XX:NewSize=10m -XX:MaxNewSize=10m -XX:InitialHeapSize=20m -XX:MaxHeapSize=20m -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=10m -XX:MaxTenuringThreshold=15 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:dynamicheck.log
Copy the code

Code:

Let’s run the code directly and then look directly at the log file:

Java HotSpot(TM) 64-bit Server VM (25.281-B09) for BSD-AMD64 JRE (1.8.0_281-B09) Built on Dec 9 2020 12:44:49 by "java_re" with GCC 4.2.1 Compatible Apple LLVM 10.0.0 (clang-1000.11.45.5) Memory: built on Dec 9 2020 12:44:49 by "java_re" with GCC 4.2.1 Compatible Apple LLVM 10.0.0 (clang-1000.11.45.5) Memory 4k page, physical 16777216k(106332k free) /proc/meminfo: CommandLine flags: -XX:InitialHeapSize=20971520 -XX:MaxHeapSize=20971520 -XX:MaxNewSize=10485760 -XX:MaxTenuringThreshold=15 -XX:NewSize=10485760 -XX:OldPLABSize=16 -XX:PretenureSizeThreshold=10485760 -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:SurvivorRatio=8 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -xx :+UseConcMarkSweepGC -xx :+UseParNewGC 0.117: [Allocation Failure (GC) 0.118: [ParNew: 7115K->619K(9216K), 0.0029447 secs] 7115K->619K(19456K), 0.0033789 secs [Times: Sys =0.00, real=0.00 secs] 0.122: [Allocation Failure (GC) 0.122: [ParNew: 7223K->0K(9216K), 0.0020159secs] 7223K->0K(9216K), 0.0020159secs] [Times: User =0.01 sys=0.00, real=0.00 SECS] Heap PAR new Generation Total 9216K, used 2212K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000) eden space 8192K, 27% used [0x00000007bec00000, 0x00000007bee290e0, 0x00000007bf400000) from space 1024K, 0% used [0x00000007bf400000, 0x00000007bf400000, 0x00000007bf500000) to space 1024K, 0% used [0x00000007bf500000, 0x00000007bf500000, 0x00000007bf600000) concurrent mark-sweep generation total 10240K, used 601K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000) Metaspace used 2713K, capacity 4486K, committed 4864K, reserved 1056768K class space used 291K, capacity 386K, committed 512K, reserved 1048576KCopy the code

Some code analysis:

We now allocate three 2M objects in a row, and one 300K object, and set array1 to NULL. The heap diagram should look something like this

Next, we need to allocate another 2M object. At this time, can Eden continue to allocate space?

Definitely not, because the Eden area is only 8M.

At this point, the young GC is executed to clean up the space.

Next, let’s look at the log file:

ParNew: 7115K->619K(9216K)

Note Before GG, 7115K is occupied, including three 2M objects, 300K objects, and hundreds of UNKNOWN objects. After GC, only 619K objects are left, including 300K objects and unknown objects.

The newly created 2m object is then allocated to the Eden area

At this point, we have to observe an important point: that is, the FROM region is 1m, which is 1024K. Now, there are 619K objects in the FROM area, more than half of the from area.

Let’s move on to the code:

Execute this code. Two 2m objects and one 300K object will be added to the heap, and array3 will be set to null.

Byte [] array4 = new byte[2*_1MB];

Then there won’t be enough space in Eden. This is when the second Young GC is triggered.

Let’s continue with the log for the second Young GC:

ParNew: 7223K->0K(9216K)

What does that mean?

Before GC, a total of 7223K objects were used, including 3 2m objects +300K objects in Eden area and 300K objects + unknown objects in FROM area. After GC, the whole new generation is free.

In theory, array2 still references 300K objects after GC. So, you can be sure that this 300K object is not going to be recycled.

But now GC logs clearly tell us that the space usage of the new generation after GC is 0.

Why is that?

Take your time, let’s continue to look at the old space log:

concurrent mark-sweep generation total 10240K, used 601K

You see, 601K was used in the old age. In fact, 601K is the space between 300K objects and unknown objects.

Why are they in the old days?

Because it triggers dynamic age judgments.

If you think about it, first of all, 300K is not a big object. (- XX: PretenureSizeThreshold = 10 m)

Also did not reach the age of 15, because only young GC twice. (- XX: MaxTenuringThreshold = 15)

And survivor is now 1024K, which is large enough to hold 601K of surviving objects. So, none of this is what causes objects to age.

Now because of two Young GCS, the 600K object is alive and takes up more than half the size of the survivor zone. Thus triggering dynamic spatial judgment, into the old age.

At this point, I believe you should be able to understand. If you still don’t understand, welcome to discuss with turnip wechat.