An article to understand JavaScript memory leaks, garbage collection mechanisms

你越是认真生活,你的生活就会越美好 —— Frank Lloyd Wright (fruits of life documentary)

勤学如春起之苗,不见其增,日有所长;
辍学如磨刀之石,不见其损,日有所亏。 —— Tao Yuanming

1. What is a memory leak?

The operation of the program is required 内存. As long as the program requires it, the operating system or runtime (runtime) must be provided 内存.

For continuous operation 服务进程(daemon), a must 及时释放不再用到的内存. Otherwise, the memory usage will become higher and higher, which will affect the performance of the system or cause the process to crash.

Insert picture description here

不再用到的内存,没有及时释放,就叫做内存泄漏(memory leak)

Some languages ​​(such as C language) must release memory manually, and the programmer is responsible for memory management.

char * buffer;
buffer = (char*) malloc(42);

// Do something with buffer

free(buffer);

The above is the C 语言code, malloc方法used to apply for memory, after using it, you must free方法release the memory by yourself .

This is very troublesome, so most languages ​​provide automatic memory management to reduce the programmer's burden. This is called " 垃圾回收机制"( garbage collector).

Two, garbage collection mechanism

How does the garbage collection mechanism know which memory is no longer needed?

The most commonly used method is called " 引用计数" (reference counting): the language engine has a "reference table" that saves all the resources (usually various values) in the memory 引用次数. If the number of references to a value is 0, it means that the value is no longer used, so this memory can be released.
Insert picture description here

In the above figure, the two values ​​in the lower left corner have no references, so they can be released.

If a value is no longer needed, but the number of references is not 0, the garbage collection mechanism cannot release this memory, which will result 内存泄漏.

const arr = [1, 2, 3, 4];
console.log('hello world');

In the above code, the array [1, 2, 3, 4]is a value and will take up memory. The variable arr is the only reference to this value, so it 引用次数is 1. Although the following code does not use arr, it still does 持续占用内存.

If you add a line of code, 解除arr对[1, 2, 3, 4]引用this memory can be 垃圾回收机制released.

let arr = [1, 2, 3, 4];
console.log('hello world');
arr = null;

In the above code arr重置为null,, the [1, 2, 3, 4]reference to the pair is removed , the number of references becomes 0, and the memory can be released.

Therefore, it does not mean that 垃圾回收机制programmers will be relieved if they have. You still need to pay attention to the memory footprint: once the values ​​that take up a lot of space are no longer used, you must check whether there are still references to them. If so, you must manually dereference.

Third, the method of identifying memory leaks

How can it be observed 内存泄漏?

The rule of thumb is that if the 连续五次垃圾回收之后memory usage is larger than once, there will be 内存泄漏. This requires real-time viewing of memory usage.

Browser

ChromeView in the browser 内存占用and follow the steps below.
Insert picture description here
PS: The picture below is the window system
Insert picture description here

  1. Open 开发者工具, select Timelinepanel
  2. Check in the Capture field at the topMemory
  3. Click the record button in the upper left corner.
  4. Perform various operations on the page to simulate the user's usage.
  5. After a period of time, click the stop button in the dialog box, and the 这段时间的内存占用situation will be displayed on the panel .

If the memory usage is basically stable and close to the level, it means that there is no memory leak.
Insert picture description here
On the contrary, it is a memory leak.
Insert picture description here

Command Line

The command line can use the Nodeprovided process.memoryUsagemethod.

process.memoryUsage()

Insert picture description here

process.memoryUsageReturn an object that contains Node 进程的内存占用信息. The object contains four fields, the unit is byte, the meaning is as follows.
Insert picture description here

  • rss(resident set size): All memory usage, including instruction area and stack.
  • heapTotal: Memory occupied by "heap", including used and unused.
  • heapUsed: The part of the used heap.
  • external: The memory occupied by C++ objects inside the V8 engine.

判断内存泄漏,以heapUsed字段为准。

Four, WeakMap

As mentioned earlier, it is very important to clear references in time. However, you can't remember so much, and sometimes you forget it when you neglect it, so there are so many memory leaks.

It is better to have a way to declare when creating a new reference, which references must be cleared manually and which references can be ignored. When other references disappear, the garbage collection mechanism can release the memory. This can greatly reduce the programmer's burden, as long as you clear the main reference.

ES6 takes this into consideration and introduces two types 新的数据结构: WeakSetand WeakMap. Their references to values ​​are not counted in the garbage collection mechanism, so there will be a "Weak" in the name to indicate that it is 弱引用.

Below WeakMap, for example, to see how it was resolved 内存泄漏in the.

const wm = new WeakMap();

const element = document.getElementById('example');

wm.set(element, 'some information');
wm.get(element) // "some information"

Insert picture description here

In the above code, create a new one first Weakmap 实例. Then, one DOM 节点as a 键名deposit to this example, and as some additional information 键值, stored together WeakMapinside. At this time, the reference WeakMapinside elementis a weak reference and will not be counted in the garbage collection mechanism.

In other words, the reference count of the DOM node object is 1, not 2. At this time, once the reference to the node is eliminated, the memory it occupies will be released by the garbage collection mechanism. The key-value pair saved by Weakmap will also disappear automatically.

Basically, if you want to add data to the object without interfering with the garbage collection mechanism, you can use it WeakMap.

WeakMap example

WeakMapThe example is difficult to demonstrate, because it is impossible to observe the reference inside it will automatically disappear. At this time, all other references are removed, and there is no longer WeakMapthe key name pointed to by the reference , which makes it impossible to verify whether the key name exists.

I couldn't think of a way until one day it was 贺师俊老师prompted that if the value pointed to by the reference occupies a lot of memory, it can be seen through the process.memoryUsagemethod.

Based on this idea, 网友 vtxfthe following example is added.
First, open it Node 命令行.

node --expose-gc

In the above code, it --expose-gc参数means that it is allowed 手动执行垃圾回收机制.

Then, execute the following code.

// 手动执行一次垃圾回收,保证获取的内存使用状态准确
> global.gc(); 
undefined

// 查看内存占用的初始状态,heapUsed 为 4M 左右
> process.memoryUsage(); 
{
    
     rss: 21106688,
  heapTotal: 7376896,
  heapUsed: 4153936,
  external: 9059 }

> let wm = new WeakMap();
undefined

> let b = new Object();
undefined

> global.gc();
undefined

// 此时,heapUsed 仍然为 4M 左右
> process.memoryUsage(); 
{
    
     rss: 20537344,
  heapTotal: 9474048,
  heapUsed: 3967272,
  external: 8993 }

// 在 WeakMap 中添加一个键值对,
// 键名为对象 b,键值为一个 5*1024*1024 的数组  
> wm.set(b, new Array(5*1024*1024));
WeakMap {
    
    }

// 手动执行一次垃圾回收
> global.gc();
undefined

// 此时,heapUsed 为 45M 左右
> process.memoryUsage(); 
{
    
     rss: 62652416,
  heapTotal: 51437568,
  heapUsed: 45911664,
  external: 8951 }

// 解除对象 b 的引用  
> b = null;
null

// 再次执行垃圾回收
> global.gc();
undefined

// 解除 b 的引用以后,heapUsed 变回 4M 左右
// 说明 WeakMap 中的那个长度为 5*1024*1024 的数组被销毁了
> process.memoryUsage(); 
{
    
     rss: 20639744,
  heapTotal: 8425472,
  heapUsed: 3979792,
  external: 8956 }

Insert picture description here

In the above code, as long as the external reference disappears, the internal reference of WeakMap will be automatically cleared by garbage collection. This shows that with its help, solving memory leaks will be much simpler.


谢谢你阅读到了最后~
期待你关注、收藏、评论、点赞~
让我们一起 变得更强


Original link
JavaScript Memory Leak Tutorial-Teacher Ruan Yifeng

It is recommended to read
JavaScript scope and variable promotion
Vue source code learning

Guess you like

Origin blog.csdn.net/weixin_42752574/article/details/111088329