Node.js chapter 5 memory Control Reading Notes

With the development of Node, JavaScript is no longer limited to the browser. This article does not discuss scenarios where web applications and command-line tools are executed in a short time and only affect end users. Since the running time is short, memory is freed as the process exits and there is little need for memory management. However, with the widespread use of Node on the server side, JavaScript memory management needs to be taken seriously.

V8 memory limits

In a normal back-end development language, there is no limit to the basic memory usage, whereas when using memory in JavaScript in Node, you will find that you can only use partial memory (about 1.4GB for 64-bit systems and 0.7GB for 32-bit systems). This limitation will result in Node not being able to manipulate large memory objects directly.

The main reason for this problem is Node’s JavaScript execution engine V8.

In V8, all JavaScript objects are allocated via the heap. Node provides a method for viewing memoryUsage in V8, process.memoryusage ().

  • heapTotalAllocated heap memory
  • heapUsedHeap memory currently in use

Why V8 limits the heap size:

  1. V8 was designed for browsers and is unlikely to encounter scenarios that use a lot of memory
  2. Limitations of V8’s garbage collection mechanism. (According to the official statement, taking 1.5GB of garbage collection heap memory as an example, V8 to do a small garbage collection takes more than 50ms, do a non-incremental garbage collection takes more than 1s)

V8 provides options to control how much memory is used

  • node --max-old-space-size=1700 test.jsSet the maximum memory size of the old generation, in MB
  • node --max-new-space-size=1024 test.jsSet the maximum memory size of the new generation, in KB

Unfortunately, these two maximum values need to be performed at startup. This means that the memory used by V8 cannot be automatically expanded based on usage, and when the memory allocation limit is exceeded, the process will fail.

V8’s garbage collection mechanism

V8’s garbage collection strategy is based on generational garbage collection. In V8, there are two main memory generations: the new generation and the old generation. Objects in the new generation are objects with a short lifetime, and objects in the old generation are objects with a long lifetime or resident memory.

The total size of the V8 heap is the memory space of the new generation plus the memory space of the old generation

Scavenge algorithm

The Scavenge algorithm is used to recycle garbage on a generational basis. The Cheney algorithm is used in the application of Scavenge.

Cheney algorithm is a garbage collection algorithm implemented by copying. It splits the heap memory in two, with each portion of space called semispace. Of the two Semispace Spaces, only one is in use and the other is idle. The semispace space in use becomes the From space, and the idle space becomes the To space. When we allocate objects, we allocate them first in the From space. When garbage collection begins, live objects in the From space are checked, they are copied To the To space, and space occupied by non-live objects is freed. After the replication is complete, the roles of the From space and To space are swapped.

The disadvantage of the Scavenge is that it uses only half of the heap memory, but the Scavenge avenge is superior in terms of time efficiency because it replicates only viable objects and only a small number of viable objects for short life cycles. Scavenge is a typical space-for-time algorithm that cannot be applied to all recycling applications on a large scale, but is ideally suited to the new generation.

promotion

The process of moving objects from the new generation to the old generation is called promotion.

Living objects in the From space need To be checked before being copied To the To space. Under certain conditions, objects with a long lifetime need To be moved To the old generation, that is, To complete the promotion of the object.

There are two main conditions for promotion:

  1. Whether the object has been screcycled
  2. To space has been used more than 25%

The 25% limit is worth setting because when the Scavenge avenge is completed, the To space will become the From space and subsequent memory allocation will be made in this space. If the amount is too high, it will affect subsequent memory allocation.

Mark-Sweep & Mark-Compact

V8 in its old days used a combination of Mark-sweep and Mark-compact for garbage collection.

Mark-sweep means marked clearly, and it is divided into two stages, marked and swept. Mark-sweep iterates over all objects in the heap during the marking phase and marks living objects, and in the subsequent cleaning phase, only unmarked objects are cleared.

The biggest problem with Mark-Sweep is the discontinuous state of memory space after a Mark Sweep collection. This fragmentation can cause problems for subsequent memory allocation because it is likely that a large object will need to be allocated, and garbage collection will be triggered ahead of time, which is not necessary.

In order to solve mark-Sweep’s memory fragmentation problem, Mark-Compact was proposed. Mark-compact stands for mark-sweep and is based on mark-sweep. The difference is that after an object is marked as dead, the living object is moved to one end during the collation process. When the move is complete, the memory outside the boundary is cleared directly.

The following table provides a simple comparison of the three main garbage collection algorithms

As you can see from the table, between Mark-Sweep and Mark-Compact, since mark-Compact requires moving objects, it is unlikely to perform very fast, so V8 mainly uses Mark-sweep as a trade-off. Mark-compact is used when there is not enough space to allocate objects promoted from the new generation.

Incremental Marking

To avoid inconsistencies between the JavaScript application logic and what the garbage collector sees, all three algorithms for garbage collection need to pause the application logic, a behavior known as “stop-the-world.”

Due to the small space of Cenozoic configuration and fewer surviving objects, the total pause has little effect on Cenozoic. However, the old generation is usually configured with a large space, and there are many living objects, and the pause caused by the actions of mark, clean, and sort of full garbage collection will be more terrible.

To reduce the pause time caused by full-heap garbage collection, V8 started with Incremental Marking, where actions that were supposed to be completed in one go are broken down into many small “steps” that allow JavaScript application logic to execute for a short time. Garbage collection and application logic alternate until the tagging phase is complete.

V8’s incremental markup has reduced the maximum pause time for garbage collection to about 1/6.

Viewing GC Logs

The main way to view the garbage collection log is to add the — trace_GC parameter at startup.

summary

  1. Node’s JavaScript execution engine is V8, and memory usage and controls are limited to V8.
  2. V8 divides memory into new generation and old generation, and stores objects with short and long lives or resident memory respectively.
  3. The Scavenge algorithm is used in the new generation to recycle garbage. It is fast and has no memory debris, but takes up double the memory space.
  4. In the old generation, mark-sweep and Mark-Compact algorithms are combined, mainly using Mark-sweep. The advantage is that objects are not moved and the disadvantage is that memory fragmentation is generated. Mark-compact is a complement to Mark-Sweep, defragmenting memory when there is not enough space to allocate newly promoted objects, which is slower due to moving objects.
  5. V8 uses Incremental Marking to reduce the impact of total pauses.