Memory space classification

Reference type data is stored in heap memory, and allocation of heap memory and garbage collection are performed by the V8 engine. V8 internal garbage collection strategy is mainly based on generational garbage collection mechanism.

Memory space is mainly divided into two types: new generation space, old generation space.

  • The new generation stores objects that live in memory for a short time, usually temporarily allocated memory, as quickly as they come and go.
  • The old generation space holds some objects that reside in memory for a long time

In the evolution of automated garbage collection, it was found that there was no single garbage collection algorithm that would work for any scenario. Because objects stay in memory for varying lengths of time, different algorithms work best for specific scenarios. Therefore, garbage collection is divided into different generations according to the lifetime of the object, and then the most efficient algorithm is applied for each generation.

Garbage collection algorithm

The New generation — Scavenge

The Cenozoic space is divided into two parts — From and To.

The From space is used To allocate memory. When the garbage collection algorithm is executed, it checks the surviving objects in the From space and copies these objects To the To space. Before copying, it makes judgment. After all the execution is completed, the living objects are placed in the To space in turn. At this time, the two Spaces are switched, also known as flipping. The To space is used as the new From space, and the original From space is used as the new To space, and so on and so on.

Characteristics: Due to its partition mechanism, it can only use half of the space of the Cenozoic era. However, due to the small number of viable objects in the Cenozoic era, its efficiency is excellent, and it is a typical algorithm that sacrifices space for time.

Promotion condition

If an object survives multiple garbage collections, it will be promoted from the new generation to the old generation and managed using a different algorithm. The specific promotion rules are as follows:

  1. Determine whether the object is recycled using the Scavenge algorithm.
  2. Judgmental CenozoicToWhether the space is occupied more than 25%.

The 25% limit is due To the Scavenge algorithm, the To space is converted To the From space, and the excessive amount of used memory can affect subsequent memory allocation

The old generation

Mark Sweep / Mark Compact

Mark Sweep, Mark Compact.

  1. Iterate over all objects of the old generation, marking the surviving objects
  2. Reclaim unmarked objects
  3. When the fragmentation space of the old generation is insufficient to allocate memory for objects promoted from the new generation, mark defragmentation is performed to remove memory fragmentation.

The biggest problem with Mark Sweep was that the reclaimed memory generated a lot of fragmentation, which was not conducive to subsequent memory allocation, so the Mark Compact was proposed to clean up the memory. What is memory fragmentation?

In the figure, the white area represents unallocated memory. Since memory allocation must use continuous addresses, scattered memory can not cope with large objects, in this case, we need to use tag collation: move the surviving objects to one end, after the completion of the move, directly clean up the remaining memory, complete collation and reclamation.

Incremental Marking

All the above three algorithms need to pause the application logic and wait for garbage collection to complete. This behavior is called total pause. In the new generation, there are fewer objects themselves, and even total pauses have little effect. However, in the old generation, there are usually many living objects, and the pauses caused by the marking, cleaning, and collating of the whole heap garbage collection can be scary. Hence the incremental notation.

In simple terms, incremental tagging is about alternating garbage collection and application logic. By interspersing the long garbage collection process between application logic, you reduce the sense of pause. This reduces the pause time by about a sixth

V8 also introduced delayed cleanup and incremental cleanup to make cleanup and cleanup incremental. It is also planned to introduce parallel tagging and parallel cleaning to further utilize multi-core capabilities and reduce the time of each pause.

contrast

As you can see, the Scavenge algorithm only values the exploiture, because the exploiture is rare in the Cenozoic era; Tag cleanup only reclaims dead objects, because dead objects are rare in old generations. Therefore, high efficiency is guaranteed.

algorithm Mark Sweep Mark Compact Scavenge
speed medium The slowest The fastest
The space overhead Few (with fragments) Less (no fragments) Double space (no debris)
Whether to move objects no is is

Of both Mark Sweep and Mark Compact, V8 mainly uses the former, and then the Mark Compact when there is not enough memory to handle newly promoted objects

A memory leak

Garbage collection is one of the performance factors that can cause memory leaks. Understanding how garbage collection works can help us develop better coding habits. In addition, to improve the efficiency of garbage collection, you need to have as few garbage collections as possible, especially full-heap garbage collection.

Take the session realization in the Web server as an example, generally through memory storage, but when the traffic is large, it will lead to a sudden increase of old generation, not only cleaning/sorting process time-consuming, but also cause memory strain or even overflow, resulting in program crash and exit.

The causes of memory leaks are as follows:

  1. The cache
  2. Scoped not released (global variable references and closures)

The cache

JavaScript developers always like to use key-value pairs of objects as caches, but this is different from strict caching. The difference is that strict caches have a well-developed expiration policy, whereas key-value pairs usually don’t.

If you want to cache in this way, be sure to set a cache size. If you use arrays for caching, limit their length and use FIFO (first-in, first-out) to eliminate them. However, this elimination strategy is relatively simple and inefficient. It is only suitable for small application scenarios. More efficient caches can be eliminated using LRU (least recently used algorithm), and the specific content of the algorithm is not expanded.

Scoped release

The global scope is not released until the process exits, so variables in the global scope are always referred to and therefore cannot be released unless they are voluntarily released: for example, delete deletes the property, or explicitly assign it to undefined or NULL.

Closures, too, need to be used with care. Good ones are magic, bad ones are junk.

other

  • The article from the summary of “simple NodeJS” – Pu Ling
  • How does the V8 engine recycle garbage memory?