In-depth understanding of JVMS – real combat old age optimization

“This article has participated in the good article call order activity, click to see: back end, big front end double track submission, 20,000 yuan prize pool for you to challenge!

preface

From the previous article, we can know that the old FULL GC in JVM optimization has a great impact on the system and garbage collector behavior, such as the CMS concurrent flag or collection cannot hold up to pause the user thread and call the Serrial collector to help the single-thread efficient collection action. But it also comes with the long Stop World time.

In summary, vintage optimization is a core part of JVM optimization, so this section will explain how to optimize vintage recycling so that objects are recycled in the younger generation rather than in the older generation.

These reviews

In the previous article, we had a detailed understanding of JVM generational and garbage collection, as well as the main garbage collectors prior to JDK9, the ParNew collector and the CMS collector, and a complete description of the details of CMS, which are very basic but very important knowledge. This article builds on the previous knowledge, using a simulated example to show you how to tune for the old JVM.

Case of actual combat

The case will be based on a very ideal simulation scenario, because the performance of the application can actually affect the performance of the system, and even the quality of the code can affect the performance of the system, so the following simulation scenarios are hypothetical, do not take the parameters of this case too seriously.

The general background of an e-commerce system:

If an e-commerce site has 20 visits per person per day, if it needs hundreds of millions of requests it needs 5 million requests per day, and if those 5 million people follow the standard of 10% ordering, then 500,000 people will place orders every day, and the orders will be paid within 4 hours according to 2/8 principle. Then the occupation at this time is about 500,000/4 hours == 500,000/14400, about 34 orders per second, in this case, it is found that the impact of the system will not be very big, the old recycling is about a few hours, completely acceptable.

High concurrency scenarios

However, in the seckill scenario, the situation is different, if 1000 orders in a second, how to deal with it? Let’s assume that if we have three machines, each machine needs to process at least 300 requests.

Calculate JVM consumption

Based on the above simulation scenario, assuming 300 requests per second based on 1KB per object, each machine will process about 300KB of memory. If the processing object of an order system is magnified 10 times, it will be 3000KB. If other operations such as order processing are included, it will need 3000KB = 30MB.

If the virtual machine stack is 1 MB each, then hundreds of threads require hundreds of meters of space. For a 4-core 8GB machine, allocate 4 GB to the JVM, and allocate 1 GB of the 4 GB to the VM stack 500M + M, method area: 256M, and out-of-heap memory: 256M. At the same time, the memory guarantee mechanism is enabled (no parameters need to be specified after JDK6) and the new generation and the old generation are allocated 1.5 GB each.

According to the above conversion, we find that if 30M objects come every second, then the EDEN region of about 1200M (8:1: The ratio of 1 is 1200 to EDEN), leaving about 200 MB of memory in the SURVIOR region. However, if the SURVIOR region does not fit, it will enter the old age. According to the previous parameters, the SURVIOR region of 150M cannot be stored. These objects are allocated to the old age.

At this rate the new generation will fill up in less than a minute. About 8 or 9 minor GCS result in a full GC, which means that it takes 8 or 9 minutes to trigger an old gc, which is a very high probability and can cause the system to stall and user threads to stop.

However, if the Survior space is sufficient, then the collection into the Survior space at this point is basically also collected for garbage objects in the next minor GC.

Optimization of garbage collection

The above case optimization is also very simple. Before explaining the final optimization scheme, we follow the following steps for analysis:

Check whether the Survior region is guaranteed to be entered by all minor GC each time

First, we need to determine whether the Survior region is accessible to all Cenozoic dwellers after garbage collection. Obviously, the Survior region is around 150M in size, and the surviving objects after each Minor GC are usually around 200M, so it is not possible to store them.

How much object should enter the old age

As mentioned before, 30M objects are generated in one second. After Minor GC, only 100M objects are left. In other words, 100M objects survive in one minute.

So generally setting a threshold of 1M is good enough

The age through which the object enters the old age

Generally the default value of 15 is a good one. But for high-concurrency businesses, it’s a good thing that big objects get old early. Because survior has a control value of 50%, and objects that add up to 50% of the survior region are older than or equal to this age, it is sometimes worthwhile to consider making new generations older.

For example, we can set the age of the object to 7 or 8.

Specifying a garbage collector

It is important to specify the garbage collector in the parameters.

Such as: - XX: + UseParNewGCCopy the code

The final optimization parameter results

After a series of analysis above, we can determine that the fundamental problem is that the object enters the old age in advance, which leads to the Survior region becoming a display and the old age objects continue to expand, and eventually the old age is full, leading to frequent full GC. Therefore, the final optimization parameters of the case are as follows:

How to optimize old memory?

In view of the above case, let’s analyze a few more contents:

Does the old age need to open allocation guarantee failure?

Let’s see what happens if you don’t turn on allocation and the guarantee fails? If the total size of the Minor Gc is less than the total size of the Minor Gc, the Minor Gc will be accompanied by the Full Gc. If the Minor Gc is not enabled, the Minor Gc will be accompanied by the Full Gc. If the Minor Gc is not enabled, the Minor Gc will be accompanied by the Full Gc. It’s on by default.

If the total size of the old generation is less than the size of the new generation, then Full Gc will occur on every request if allocation is not turned on.

If the CMS collector is used, do you need to change 92% of the parameters

From the point of view of the case, if the old age reaches 900M after optimization, it means that the order system has been running for a long time (several hours). Generally, the SEC kill has been over long ago. At this time, the Full GC will not affect the processing of services and requests.

Possible impact on the system when full Gc is triggered in the old age

If a new generation live objects larger than 200 M after a gc, found Survior area not put, at that time, the old s judgment all previous promotion average size, found that the basic can be allocated, because usually only a few tens of M after the adjustment into the size of the object, so the probability of such is relatively small, even if that happens, At this time, the system has passed for a long time, and the peak order is usually placed in the first 10 minutes. If Fu’l Gc is not carried out in the first 10 minutes but one hour later, the operation of the order system will not be affected, because the pressure is very small at this time.

The Concurrent Mode fail condition has no impact

As in the previous analysis, if the 900M of old space is used up, the system process and the garbage collection thread are running at the same time. If the object of 200M is entered during concurrent collation, the worst case scenario is that the trigger failure causes stop World and serial to perform the single-threaded recycling action. However, what needs to be considered is that it is assumed that one hour has passed in this case, and the order pressure is much lower at this time, and the impact of Full Gc can also be borne. After this Full Gc, the next one may be several hours later, although this situation may happen, the chance is very small.

What is the probability of memory defragmentation

As in the above case, if FULL GC occurs, the system has been running for a long time. If the interval between FULL GC is very long, the cost of memory defragmentation for each FULL GC is acceptable.

conclusion

So let’s summarize this case by saying how do you think about optimization

  1. First of all, business objects are objects with a very short life cycle. The pressure of the new generation is greater than that of the old age, so it is very cost-effective to appropriately reduce the space of the old age
  2. Predict when an object enters the old age in a high-concurrency scenario. If an object often “spans” a portion of content space is wasted, it is the Survior region
  3. The approximate amount of memory required by the object in each partition, such as how much memory is required per thread
  4. Whether the age of the object needs to be changed, and whether it is good or bad to let the object into the old age in advance
  5. Pay attention to the impact of the collector on object garbage collection, and force the use of a garbage collector at startup because the default garbage collector is different for different JDK versions.