In this section, we will focus on a major area in the heap, the Young generation. First we’ll discuss why tuning the parameters of the new generation is so important to the performance of your application, then we’ll look at the JVM parameters of the new generation.

For pure JVM functionality, there is no need for a new generation to operate on the entire heap. The only reason the new generation exists is to optimize garbage collection (GC) performance. More specifically, dividing the heap into young and old has two advantages: it simplifies allocation of new objects (memory is allocated only in the new generation) and it can more efficiently clean up objects that are no longer needed (i.e. dead objects)(the new and old generations use different GC algorithms)

Through extensive research on the application of object-oriented implementation, we find a common characteristic: many objects have a very short lifetime. At the same time, it is found that newborn objects rarely refer to long-lived objects. Combining these two characteristics, it is clear that the GC frequently visits newborn objects, such as in a separate region of the heap, called the Cenozoic. In the new generation, GC can quickly mark and reclaim “dead objects” without having to scan the entire Heap for “old objects” that have been alive for some time.

SUN/Oracle’s HotSpot JVM further divides the new generation into three zones: a relatively large zone called “Eden”; The two smaller zones are called “From survivor” and “To survivor.” According to the rules, the new object will be allocated in Eden first (if the new object is too large, it will be allocated directly in the old age). In GC, objects in Eden are moved to survivor until the object reaches a certain age (defined as the number of times it has survived GC) and is moved to the old age.

Based on the assumption that most newborn objects are reclaimed in the GC. The new generation of GC uses replication algorithms. The To survivor zone remains empty until GC, objects are stored in Eden and From survivor, and surviving objects in Eden are copied To To survivor when GC runs. For surviving objects in From survivor, the object’s age is taken into account, and if the age does not reach the tenuring threshold, the object is copied To SURVIVOR. If the threshold is reached the object is copied to the old age. After the replication phase is complete, only dead objects are saved in Eden and From survivable zones, which can be considered as empty. If the To survive region is filled during replication, the remaining objects are copied To the old age. Finally, the NAME of the From survivor and To survivor will be changed, and in the next GC, the To survivor will become the From survivor.

The figure above illustrates the GC process, with dead objects in yellow, remaining space in green, and surviving objects in red

To summarize, objects are generally born in Eden. During the young GC, objects are moved between the two surviving regions, and if they survive to an appropriate age, they are moved to the old age. When an object dies in the old age, a higher level of GC, a more heavyweight GC algorithm is required (replication algorithm is not suitable for the old age because there is no extra space for replication)

Now you can see why the size of the new generation is important, if the new generation is too small, it will cause the new generation to be promoted to the old generation very quickly, and the old generation will be hard to recycle. If the new generation gets too big, too much copying happens. We need to find the right size, and unfortunately, the only way to get the right size is through constant testing and tuning. This is where the JVM parameters come in

-XX:NewSize and -XX:MaxNewSize

Just as you can specify the heap size with arguments (-xms and -xmx), you can specify the new generation size with arguments. When setting XX:MaxNewSize, you should consider that the new generation is only part of the heap, and the larger the new generation is set, the smaller the old age area. It is generally not allowed for the new generation to be older than the old generation, because in the worst case scenario of GC, all objects are promoted to the old generation. -xx :MaxNewSize The maximum value can be set to -xmx /2.

For performance, the initial size of the new generation is usually set with the parameter -xx :NewSize. It is helpful if you know the size of the object initially allocated by the new generation (which has been monitored) to save the cost of automatic generation expansion.

-XX:NewRatio

You can set the relative sizes of Cenozoic and old ages. The advantage of this approach is that the new generation size dynamically expands with the entire heap size. Parameter -xx :NewRatio Sets the ratio of the old generation to the new generation. For example, -xx :NewRatio=3 specifies that the old/Cenozoic era is 3/1. The old age accounts for three-quarters of the heap size, and the Cenozoic one quarter.

Absolute values work if you define both absolute and relative values for the new generation. $Java -xx :NewSize=32m -xx :MaxNewSize=512m -xx :NewRatio=3 MyApp

With the above Settings, the JVM will attempt to allocate a quarter of the heap size for the new generation, but not less than 32MB or more than 521MB

There is no general rule on whether to use absolute or relative values in setting the size of the new generation. If you know your application’s memory usage, it’s better to have a fixed size heap and a new generation, but you can also set relative values. If you don’t know anything about your application’s memory usage, the right thing to do is not to set any parameters if your application is running well. Good. We don’t have to do anything extra. If you encounter performance or OutOfMemoryErrors, you first need to perform a series of purposeful monitoring tests to narrow down the root cause of the problem before tuning.

-XX:SurvivorRatio

The parameter -xx :SurvivorRatio is similar to that of -xx :NewRatio, which applies to the inner zone of Cenozoic era. -xx :SurvivorRatio Specifies the ratio of Eden to SurvivorRatio. For example, -xx :SurvivorRatio=10 indicates that Eden is 10 times the size of SurvivorRatio To (and SurvivorRatio From). Therefore, Eden accounts for 10/12 of the Cenozoic size, and the surviving areas From and To each account for 1/12 of the Cenozoic size. Note that the two survival zones are always the same size..

What is the effect of setting the size of the survival zone? Assuming that the survival zone is too small compared to Eden, the Corresponding new object’s Eden will always have a large space. Of course, we hope that if all these objects are recovered during GC, Eden will be emptied and everything will be normal. However, if a number of objects survive the GC, there is very little room for them in the survival zone. As a result, most of the surviving objects will be moved to the old age after one GC, which is not desirable. Consider the reverse case, assuming that the survivability zone is too large relative to Eden, there is of course enough space for surviving objects after GC. However, too small Eden means that the space will run out faster and increase the number of GC in the new generation, which is unacceptable.

In summary, we want to minimize the number of short-lived objects promoted to the old generation, as well as the number and duration of the new generation GC. We need to find a compromise for our current application, and the starting point is to understand the age distribution of objects in our current application.

-XX:+PrintTenuringDistribution

Parameters – XX: + PrintTenuringDistribution specify the JVM in each new generation of GC, output survival area of the age distribution of the object. Example: ‘Desired survivor size 75497472 bytes, new threshold 15 (Max 15)

  • age 1: 19321624 bytes, 19321624 total
  • age 2: 79376 bytes, 19401000 total
  • age 3: 2904256 bytes, 22305256 total`

The first line states that the survival zone To size is 75 MB. There is also information about the tenuring threshold, which means that the object has passed several GCS before moving from the new generation To the old age (i.e., the maximum age the object can reach before being promoted). In the example above, the old age threshold is 15 and the maximum is 15.

The next line shows the number of bytes of objects in this age for each object age less than the old age threshold (this line is ignored if there are no objects in the current age). In the example above, the object survived about 19 MB after one GC, 79 KB after two GC, and 3 MB after three GC. At the end of each line, display all object sizes up to this age. So, the total on the last line indicates that the surviving area To is occupied by a total of 22 MB. The total size of the surviving area To is 75 MB, and the current old age threshold is 15, so it can be inferred that no objects will be moved To the old age in this GC. Now assume that the next GC output is:

`Desired survivor size 75497472 bytes, new threshold 2 (max 15)

  • age 1: 68407384 bytes, 68407384 total
  • age 2: 12494576 bytes, 80901960 total
  • age 3: 79376 bytes, 80981336 total
  • age 4: 2904256 bytes, 83885592 total`

Compare the previous old age distribution. Clearly, objects of ages 2 and 3 remain in the survival zone, as we see that objects of ages 3 and 4 are the same size as those of ages 2 and 3. At the same time, it is found that some objects in the survival area have been reclaimed, because the size of the object of age 2 is 12MB, while the size of the object of age 1 was 19 MB in the previous time. Finally, you can see that in the latest GC, 68 MB of new objects were moved from the Eden garden to the survivable zone.

Note that the total size of the GC surviving area is 84 MB – greater than 75 MB. As a result, the JVM lowers the age threshold from 15 to 2, and on the next GC, a portion of objects are forced out of the survival zone, which may be reclaimed (if they happen to die) or moved to the age.

-XX:InitialTenuringThreshold, -XX:MaxTenuringThreshold and -XX:TargetSurvivorRatio

Parameters – XX: + PrintTenuringDistribution parts of the output value can be controlled by other parameters. Through – XX: InitialTenuringThreshold and – XX: MaxTenuringThreshold can set the initial value of the old s threshold and the maximum value. In addition, you can set the target utilization rate of a survivable zone with the -xx :TargetSurvivorRatio parameter. For example, -xx :MaxTenuringThreshold=10 -xx :TargetSurvivorRatio=90 Sets the upper limit of the old age threshold to 10 and the survivorship space target utilization rate to 90%.

There are many ways to set the behavior of the new generation. There is no universal formula. We must be aware of the following 2 situations: 1 if we find from the age distribution that there are many objects whose age continues to increase before reaching the old age threshold. This indicates that -xx :MaxTenuringThreshold is set by 2 if the value of -xx :MaxTenuringThreshold is greater than 1, but many objects are never older than 1. You should look at the survivorship target utilization. If the survivor usage is never reached, this means that the objects are all collected by GC, which is exactly what we want. Some objects older than 1 are moved to the old age if the surviving area is frequently used. In this case, you can try to adjust the survivorship size or target utilization.

-XX:+NeverTenure and -XX:+AlwaysTenure

Finally, we introduce two rather rare parameters that correspond to two extreme Cenozoic GC scenarios. Set -xx :+NeverTenure. The object will never be promoted to the old age. We can do this when we are sure we don’t need the old age. This setup is risky and wastes at least half of the heap memory. Instead, set the parameter -xx :+AlwaysTenure to indicate that there are no surviving zones and all objects will be promoted to the old age on the first GC. There is no logical scenario to use this parameter. It’s interesting to see what happens with this setup in a test environment. However, these parameters are not recommended.

Conclusion It is very important to configure Cenozoic properly, and there are many parameters to set Cenozoic. However, adjusting for the new generation alone, without considering the old, is unlikely to succeed. When adjusting heap and GC Settings, we should always consider both generation and age.

In the next two parts of this series, we will discuss old GC strategies in HotSpot JVMS. We will learn about “throughput GC collector” and “Concurrent low-latency GC collector” as well as the basic principles, algorithms and tuning parameters of the collector

That’s it! Stay tuned for more next time!