Common JVM parameter configuration and GC performance optimization

Common JVM parameter configuration

Garbage Collection Statistics

-XX:+PrintGC Print GC brief information
-XX:+PrintGCDetails print GC detailed information
-XX:+PrintGCTimeStamps print the time stamp of CG occurrence
-Xloggc:log/gc.log Specify the location of GC log and output it as a file
-XX: +PrintHeapAtGC Print heap information before and after each GC.

heap settings

-Xms: Initial heap size, minimum heap
-Xmx: Maximum heap size
-Xmn: Set the size of the new generation
-XX: NewRatio The ratio of the new generation to the old generation, if it is 3, it means the ratio of the young generation to the old generation is 1 : 3, the young generation accounts for 1/4 of the sum of the entire young generation and the old generation
-XX:SurvivorRatio sets the ratio of the two Survivor areas to eden. Note that there are two Survivor areas. For example: 8, means Eden: Survivor=8:2, a Survivor area occupies 1/10 of the entire young generation
-XX:PermSize: Set the initial space of the permanent area
-XX:MaxPermSize: Set the maximum space of the permanent area.
-XX:+MaxTenuringThreshold=10: The maximum age of the new generation of garbage, which means that the object enters the old age after 10 copies in the Survivor area. If it is set to 0, the young generation objects will directly enter the old generation without going through the Survivor area.
-XX:+PretenureSizeThreshold: Set the threshold for large objects to enter the old age directly. When the size of the object exceeds this value, it will be directly allocated in the old generation. 

stack allocation parameters

-Xss: Set the size of the stack space

Garbage collector settings

Settings for the serial collector

-XX:+UseSerialGC: Set the serial collector, which is generally suitable for small applications and single processors. The algorithm is relatively simple and the GC efficiency is high, but it may bring pauses to the application.

Parallel collection collector settings (the goal of the ParallelGC collector is to achieve a manageable throughput)

-XX:+UseParNewGC: Set young generation for parallel collection.
-XX:+UseParallelGC: Set the young generation to use the parallel collection collector. Multiple threads execute GC in parallel, which is generally applicable to multi-processor systems and can improve the efficiency of GC, but the algorithm is complex and the system consumes a lot.
-XX:+UseParalledlOldGC: Set the old generation as a parallel recycling collector, which only appeared after Java1.6.
-XX:ParallelGCThreads=n: Set the number of threads used by the parallel collector to collect, preferably equal to the number of CPUs.
-XX:MaxGCPauseMillis=n: Set the maximum pause time for each parallel garbage collection of the young generation.
-XX:GCTimeRatio=n: Set the percentage of garbage collection time to program running time. The formula is 1/(1+n)
-XX:+UseAdaptiveSizePolicy: Adaptive policy, which automatically selects the size of the young generation area and the corresponding ratio of the Survivor area.

CMS concurrent collector (with the shortest pause as the goal)

-XX:+UseConcMarkSweepGC: Use CMS memory collection.
-XX:+ParallelCMSThreads: Set the number of CMS threads. 
-XX:CMSFullGCsBeforeCompaction: After how many times CMS performs memory compression, since the concurrent collector does not compress and organize the memory space, "fragmentation" will be generated after running for a period of time, which reduces the operating efficiency.
-XX:+UseCMSCompactAtFullCollection: Compression of the old generation during FULL GC. CMS does not move memory, so this is very prone to fragmentation, resulting in insufficient memory, so memory compression will be enabled at this time. Might affect performance, but eliminates fragmentation.
-XX:+CMSInitiatingOccupancyFraction: Set the CMS collector to trigger after the old age space is used, the default is 68%. 
-XX:+CMSClassUnloadingEnabled: Allows recycling of class metadata.
-XX:+CMSParallelRemarkEndable: Enable parallel remark. 
-XX:CMSInitatingPermOccupancyFraction: When the permanent area occupancy reaches this percentage, start CMS recovery (provided that -XX:+CMSClassUnloadingEnabled is activated). 
-XX:UseCMSInitatingOccupancyOnly: Indicates that the CMS recycling will only be performed when the threshold is reached. 
-XX:+CMSIncrementalMode: Use incremental mode, which is more suitable for single CPU. 

G1 collector

-XX:+UseG1GC: Use the G1 collector. 
-XX:+UnlockExperimentalVMOptions: Allow experimental parameters. 
-XX:+MaxGCPauseMills: Set the maximum garbage collection pause time. 
-XX:+GCPauseIntervalMills: Set the pause interval. 

GC performance optimization of JVM

There are mainly two indicators for GC performance: throughput (working time is not counted, the ratio of gc time to the total time) and pause time.

heap size

By default, vm will increase/decrease the heap size to maintain the proportion of free space in the entire vm, which is specified by MinHeapFreeRatio and MaxHeapFreeRatio.

Generally speaking, the app on the server side will have the following rules:

(1) Allocate as much memory as possible to vm;
(2) Set Xms and Xmx to the same value. If the memory used by the virtual machine is relatively small when it is started, and many objects need to be initialized at this time, the virtual machine must repeatedly increase the memory.
(3) As the number of processor cores increases, the memory also increases.

young generation

(1) The factor that affects the smooth operation of the program is the size of the new generation. The larger the young generation, the fewer minor collections; but when the heap size is fixed, the larger the young generation, the smaller the old generation, and more major collections.
(2) 8NewRatio reflects the size ratio between the new generation and the old generation. NewSize and MaxNewSize reflect the lower limit and upper limit of the size of the young generation. Setting these two values ​​to be the same will fix the size of the young generation (same as Xms and Xmx).
(3) SurvivorRatio can also optimize the size of survivor, but this has little impact on performance. SurvivorRatio is the size ratio between Eden and Survior.

Generally speaking, the app on the server side will have the following rules:

(1) First determine the maximum heap size that can be allocated to the vm, and then set the optimal young generation size; (
2) If the heap size is fixed, increasing the size of the young generation means reducing the size of the old generation. Make the old generation large enough to hold all surviving objects at any time (leave 10%-20% free).

young generation size selection

(1) Application of response time priority: set it as large as possible until it is close to the minimum response time limit of the system. In this case, the frequency of young generation collection is also the smallest, and at the same time, reduce the number of objects reaching the old generation.
(2) Applications with throughput priority: Set it as large as possible, possibly reaching the level of Gbit, because there is no requirement for response time, and garbage collection can be performed in parallel, which is generally suitable for applications with more than 8 CPUs.
(3) Avoid setting too small. When the new generation setting is too small, it will lead to: ①YGC times more frequent; ②It may cause YGC objects to directly enter the old generation. If the old generation is full at this time, FGC will be triggered.

Old generation size selection

(1) Applications with priority on response time: the old generation uses concurrent collectors. If the heap setting is small, it may cause memory fragmentation, high recycling frequency, and application suspension, so the traditional mark-and-sweep method is used; if the heap is large, it will take a long time to collect. Generally, you need to refer to the following data:
         concurrent garbage collection information, the number of concurrent collections in the permanent generation, traditional GC information, and the proportion of time spent on young generation and old generation collection.
(2) Applications that prioritize throughput: Generally, applications that prioritize throughput have a large young generation and a small old generation, so that most short-term objects can be recycled as much as possible, and mid-term objects can be reduced. The old generation only stores long-lived objects.

Fragmentation issues caused by smaller heaps

Because the concurrent collector of the CMS old generation uses a mark-and-sweep algorithm , it does not compact the heap . When the collector reclaims, it will merge adjacent spaces so that they can be allocated to larger objects. However, when the heap space is small, "fragmentation" will appear after running for a period of time. If the concurrent collector cannot find enough space, the concurrent collector will stop. The following configuration may be required:

-XX:+UseCMSCompactAtFullCollection: When using the concurrent collector, turn on the compression of the old generation.
-XX:CMSFullGCsBeforeCompaction=0: When the above configuration is enabled, how many times of Full GC is set here to compress the old generation.

other instructions

(1) With a 64-bit operating system, the 64-bit jdk under Linux is slower than the 32-bit jdk, but it consumes more memory and greater throughput

(2) The XMX and XMS settings are the same size, and the MaxPermSize and MinPermSize settings are the same size, which can reduce the pressure brought by the scaling heap size

(3) The goal of CMS is the shortest GC pause time. The advantage of using CMS is to use as few young generations as possible, and then the old generation uses CMS to collect in parallel, which can ensure the throughput efficiency of the system with low latency

(4) When the system stops, it may be a GC problem or a program problem. Use jmap and jstack to check, or killall -3 java, and then check the java console log, you can see many problems

(5) If the cache is used, the old generation should be larger, and the cached HashMap should not be unlimited in length. It is recommended to use the LRU algorithm for the cache. The maximum length of the LRUMap should also be set according to the actual situation.

(6) When using concurrent recycling, the young generation is smaller and the old generation is larger, because the old generation uses concurrent recycling, even if it takes a long time, it will not affect other programs to continue running, and the website will not stop

(7) The setting of JVM parameters (especially the setting of parameters such as –Xmx –Xms –Xmn -XX:SurvivorRatio -XX:MaxTenuringThreshold) does not have a fixed formula, and needs to be measured according to the actual data of the PV old area, the number of YGCs, etc. . In order to avoid promotion faild, the xmn setting may be too small, which also means that the number of YGCs will increase, and the ability to handle concurrent access will decrease. The tuning of each parameter requires detailed performance testing to find the best configuration for a particular application.

promotion failed: (promotion failed)

Promotion failed during garbage collection. Generally, there may be two reasons. The first reason is that the To survivor space is not enough, and the objects in the space should not be moved to the old generation, but there are many objects in the young generation that need to be placed. Salvage space; the second reason is that the old generation does not have enough space to accept objects from the young generation; in both cases, it will turn to Full GC, and the website will pause for a long time.

solution:

  • The solution to the first reason is to remove the rescue space, just set -XX:SurvivorRatio=65536 -XX:MaxTenuringThreshold=0, but because the rescue space is not used, the old generation is easy to be full, and the Full GC execution will be more frequent, so The rescue space can be increased, so that there will be no promotion failed.
  • My solution to the second reason is to set CMSInitiatingOccupancyFraction to a certain value (assuming 70), so that the CMS will start to execute when the old generation space reaches 70%, and the old generation has enough space to accept objects from the young generation.

Performance optimization in actual programming

The following are some points that should be paid attention to in the process of actually writing programs: developing these habits can reduce unnecessary consumption of memory to a certain extent, and further reduce the continuous GC caused by insufficient memory.

(1) Reduce new objects. After each new object, a new memory space must be opened. After these objects are no longer referenced, they must be recycled. Therefore, if the object is reused reasonably to the maximum extent, or the basic data type is used instead of the object, it will help to save memory;
(2) Use more local variables and reduce the use of static variables. Local variables are created on the stack for fast access. Static variables are in heap memory;
(3) Avoid using finalize, which will add a lot of burden to GC;
(4) If it is single-threaded, try to use non-multi-thread safe, because thread safety comes from synchronization mechanism, Synchronization mechanisms can reduce performance. For example, if a single-threaded program can use HashMap, don't use HashTable. In the same way, minimize the use of synchronized
(5) Replace the multiplication and division symbols with shift symbols. eg: a*8 should be written as a<<3
(6) Use cache for frequently used objects;
(7) Try to use basic types instead of wrapper types, and try to use one-dimensional arrays instead of two-dimensional arrays;
(8) Try to Use the final modifier, final means that it cannot be modified, and the access efficiency is high;
(9) In the case of single thread (or for local variables), try to use StringBuilder for strings, which is faster than StringBuffer;
(10) Why is String slow? Because String is an immutable object, every time the String type is changed, it is actually equivalent to generating a new String object, and then pointing the pointer to the new String object. If thread safety cannot be guaranteed, try to use StringBuffer to concatenate strings. It should be noted here that the default cache capacity of StringBuffer is 16 characters. If it exceeds 16, the append method calls the private expandCapacity() method to ensure sufficient cache capacity. Therefore, if the capacity of StringBuffer can be preset, avoid append to expand the capacity. If you can guarantee thread safety, use StringBuilder.

Guess you like

Origin blog.csdn.net/vcit102/article/details/131800172