# GC profile

Garbage Collection, in its full name, is an automatic memory management mechanism. Generally, the garbage collector implemented by the corresponding language collects object memory that is no longer used by the current program under certain trigger conditions.

In Node.js, the V8 engine is responsible for GC operations, but the log information is disabled by default. You can set a series of flags to obtain different levels of V8 GC log information in real time:

  • — trace_GC: a log line briefly describes the time, type, heap size change, and cause of each GC
  • –trace_gc_verbose: Combined with — trace_GC shows the details of each V8 heap space after each GC
  • — trace_gc_nVP: Detailed key-value pair information for each GC, including GC type, pause time, memory changes, etc

V8-gc-log-parser can be used to parse GC logs directly. If you are interested in using v8-GC-log-parser, please refer to @joyeecheung at JS Interactive. Are Your V8 Garbage Collection Logs Speaking To You? .

Today’s example is tuned without changing the code’s business logic by parsing and presenting V8 GC logs on the Node.js performance platform.

# Pressure measurement phenomenon

It happened that one of our customers wanted to make some further optimizations when the CPU was 100% and the single-process QPS fluctuated around 100 when the project went online for pressure test. The first thing that comes to mind is to plug into the Node.js performance platform and do a CPU Profile in the pressure test to see where the system’S CPU consumption is:



You can see that _tickDomainCallback and garbage Collector together account for 83% of the CPU, and after talking to the user, It is found that the logic inside _tickDomainCallback consumes high CPU respectively is typeOrm and its own controller logic. Typeorm is not easy to upgrade due to API changes. The controller logic has been optimized and there is no room for improvement.

Therefore, it is natural to focus on the GC phase to further improve project performance. Avenge avenge avenge avenge Avenge Avenge Avenge avenge avenge avenge avenge avenge avenge avenge avenge avenge avenge avenge avenge avenge avenge avenge avenge avenge avenge avenge avenge avenge avenge avenge avenge avenge avenge avenge avenge avenge avenge avenge avenge avenge avenge avenge avenge



In the GC Trace result analysis graph, you can see several important information circled in red:

  • The total GC timeout is up to 47.8s, mostly scavenge
  • A total of 988 scavenge avenge avenge avenge 3min of GC tracking log
  • The average scavenge time is between 50 and 60ms

# Further analysis

In the analysis of GC Trace results above, it can be seen that GC optimization is focused on the scavenge stage, namely the memory reclamation of the new generation. Recycle the V8 Scavenge logic and the semi space allocation failed.

It can be inferred that the user’s application is frequently generating a large number of small objects in the new generation during pressure testing, resulting in the default semi space filling up quickly and triggering the flip. This is the result of the scavenge and CPU consumption during GC tracing. In this case, can we optimize by adjusting the default semi space value?

# Try optimization

## I. Semi space is set to 64M

After the semi space is adjusted to 64M, the online pressure survey is conducted and CPU Profile and GC Trace are obtained during the pressure survey, as shown below:



You can see that the CPU usage in the Garbage collector phase is down to around 7%. Let’s look at the GC trace:



The insane decrease from approximately 1000 to 294 exploiture the semi space increase to 64M, but the amount of time taken to recover each exploiture does not increase significantly and fluctuates between 50 and 60ms. As a result, the total pause time for a 3-minute GC trace went down from 48s to 12s, which corresponded to an increase in QPS for the business of about 10%.

Semi space is set to 128M

When semi space value is further increased to 128M, CPU Profile results are observed:



At this point, the garbage collector consumption is not significantly reduced compared to the previous setting of 64M. Also observe the GC trace result:



Obviously, the reason for the small increase in GC ratio compared to 64M is as follows: Although semi Space was further increased to 128M and the scavenge avenge decreased from 294 to 145 times, the recovery time per algorithm nearly doubled, so the total benefit was not significant.

## iii.Semi space is set to 256M

When the semi space is further adjusted to 256M, the results are very similar to 128M: The scavenge avenge decreases from 294 to 72 exploiture within 3 minutes, as compared to the 64M insane. However, the recovery time of each algorithm fluctuates to around 150ms, so the overall performance is not significantly improved, as shown in the figure below:



# # IV. Summary

After improving semi space values from the default setting of 16M to 64M, we can see a significant improvement in overall GC performance for Node applications, which is reflected in approximately 10% improvement in pressure QPS. However, when semi space is further increased to 128M and 256M, the benefits are not obvious. Semi space itself is also used for fast memory allocation of new generation objects, so it should not be set too large. Therefore, the optimal runtime semi space value for this project is 64M.

# Last

Runtime tuning on the GC side is a less common way to improve performance on our projects, in large part because the application runtime GC state itself is not directly exposed to the developer. From the above customer case, we can see that with the help of node.js performance platform, real-time detection of Node application GC status and corresponding optimization, making it very easy to improve project performance without changing a line of code.