preface

If you have read the JVM articles, you should have a clear idea of how the JVM’s memory is distributed. In this article, we will talk about the JVM garbage collection mechanism.

Replication algorithm, Eden zone, and Survivor zone

Let’s start by exploring how garbage collection is implemented for new generation areas of JVM heap memory.

The JVM actually divides the new generation into three zones: one Eden zone and two Survivor zones.

Eden occupies 80% of the memory space and each Survivor occupies 10% of the memory space. For example, if the Eden zone has 800M, then each Survivor zone has 100M.

The usual available areas are Eden and one of the Survivor areas, which is 900M of memory space.

At the beginning of object creation, all objects are allocated in Eden area. If Eden area is nearly full, garbage collection Young GC will be triggered, and the garbage collection process is as follows:

The surviving objects in the Eden zone are first moved into one of the empty Survivor zones at a time.

Then the Eden area is cleared, and the newly created object is placed in the Eden area again.

If the Eden region is nearly full the next time, the Young GC is triggered again, which moves the Eden region and surviving objects in the Survivor region of existing objects to another empty Survivor region, and clears the Eden region and Survivor region of previously existing objects.

So that’s the process of copying the algorithm.

Always keep a Survivor region empty for garbage collection by the replication algorithm, and this region only takes up 10% of the total memory, while the other 90% can be used, so memory utilization is still quite high.

When do you enter the old age

Let’s take a look at when we will enter the old age, which was briefly covered in the easy to understand generational model of the JVM in the previous article and will be explored in more detail today.

1. Enter the old age after avoiding 15 GC rounds

By default, if an object in the new generation has not been collected after 15 GC’s, it will be rolled into the old generation.

This number can be set by the JVM parameter “-xx :MaxTenuringThreshold”. The default value is 15.

2. Dynamic object age judgment

Another way to judge can also enter the old age, is not to wait for GC15 times.

The general rule is that if the total size of a batch of objects is greater than 50% of the size of the current Survivor region memory, then objects that are older than or equal to the age of the batch are moved to the old age.

Let’s take a look at the picture below

Assuming that there are two objects in Survivor that have both gone through two GCS and are 2 years old, and that the combined size of the two objects is more than 50M, which is more than 50% of the memory size of the Survivor region, then all objects older than 2 years in the Survivor region are moved to the old age at this point.

This is known as the dynamic age rule.

It should be noted that multiple age objects of age 1+ age 2+ age N exceed 50% of the size of the Survivor zone, and the objects older than age n are put into the old age.

3. Big objects go straight to the old age

Has a “- XX: PretenureSizeThreshold” JVM parameter, the default value is 0, said any situation is the first object is assigned to Eden area.

We can give it a byte number 1048,576 bytes, which is 1M.

This means that when the object to be created is larger than 1M, it will be placed directly into the old age, without passing through the new generation at all.

Since large objects can degrade performance when GC is performed through the copy algorithm, they can simply be put into the old age.

4. Too many objects survived after Young GC cannot be placed into Survivor zone

In other cases, there are too many surviving objects after the Young GC to fit into the Survivor zone, and these objects are moved directly to the older generation.

Here we have to think about a problem, if the old age also can not let go how to do?

Guarantee principle of old chronospatial allocation

First, before any Young GC is executed, the JVM checks to see if the memory available in the old generation is greater than the total size of all objects in the new generation.

Why check this? Because in the extreme case, after Young GC, all objects in the new generation survive, that would put all objects in the new generation into the old age.

If the available memory of the old generation is greater than the total size of the new generation objects, then it is safe to execute the Young GC.

But if the old s available memory less than the total size of the new generation of objects, this time will see a parameter “- XX: HandlePromotionFailure” is set to true (can think after jdk7, the default set to true).

If set to true, then the next step is to see if the available memory of the old age is greater than the average size of the objects that entered the old age after each Young GC.

If the available memory of the older generation is less than the average size, or if the parameter is not set to true, then “Full GC” is triggered directly, which is garbage collection of the older generation to make room for the Young GC.

If the above two cases are successful, the Full GC** is not performed, and the Young GC is performed, there are several possibilities: **

1. If the size of surviving objects after Young GC is smaller than that of Survivor zone, enter Survivor zone directly.

2. If the size of the surviving object after the Young GC is larger than the size of the Survivor region, but smaller than the size of the available memory of the old age, the old age is directly entered.

3. Unfortunately, there is no space available for these live objects in the old days and a “Handle Promotion Failure” situation will occur, triggering the Full GC.

If not enough memory is available after Full GC, the OOM will run out of memory.

This paragraph may be tedious, combined with the memory model, read twice believe that friends can understand.

Garbage collection algorithms from the old days

Next we will introduce the old garbage collection algorithm, tag collation algorithm, it is relatively easy to understand.

At the beginning of our object is random distribution, after garbage collection, will mark which is live objects, which are the garbage objects, and then will be sorted the live objects in memory to move, to move aside to go together as far as possible, and then cleaned the garbage objects, the advantage is to avoid the large fragments of the memory after garbage collection.

But this process is time-consuming, at least 10 times slower than newer garbage collection algorithms.

Therefore, if the system frequently appears Full GC, the system performance will be seriously affected, and frequent stalling occurs.

So one of the problems with JVM optimization is reducing Full GC frequency.

Garbage collector

The new generation and the old generation are recycled through different garbage collectors.

Seral and Seral Old garbage collector: used to recycle new generation and Old generation respectively.

It works in a single thread, so garbage collection stops other threads on our system, freezes the system, and then performs garbage collection, which is basically not used anymore

ParNew and CMS garbage collector: used to collect new generation and old generation respectively.

They are multi-threaded and concurrent, with better performance, and are now generally standard on online production systems.

G1 Garbage collector: Collects both the new generation and the old generation, using a better algorithmic mechanism.

Here is just to give you a simple introduction, more detailed content will be analyzed separately.

Stop the World

The JVM’s biggest pain point is stopping the World.

During garbage collection, the JVM will enter the Stop the World state in the background because it is important to keep the garbage collector focused on garbage collection (in case new objects are created during garbage collection).

Once in this state, it will stop our system worker thread and our code will no longer be running.

Then when the garbage collection is complete, the worker thread resumes and the code can continue running.

Therefore, as long as GC is experienced, the system will be stuck for a period of time. The garbage collection of the new generation may not feel too much, but the garbage collection of the old generation takes more time, and the system may be obviously felt dead.

So whether it’s the new generation of garbage collection or the old generation of garbage collection, we should try to reduce their frequency.

conclusion

Today’s dry goods content or more, I believe that partners will have a deeper understanding of the JVM after reading.

You are advised to find some information about the implementation principles of garbage collectors, which will be introduced in subsequent articles.

Well, that’s it. Leave a comment in the comments section. Your support is my motivation to update!

Previous articles recommended:

The class loading mechanism of the JVM

The JVM memory model is no longer a secret

Easily understand the generational model of the JVM