Memory leak in JavaScript

What is a memory leak?

The running of the program requires memory. As long as the program asks, the operating system or runtime must supply memory.

For a continuously running service process (daemon), the memory that is no longer used must be released in a timely manner. Otherwise, the memory usage will become higher and higher, which would affect system performance, even crash the process.

Memory leak is used to describe the failure to release unreachable memory, which can no longer be allocated again by any process during execution of the allocating process.

Some languages, such as the C, must manually free up memory, and the programmer is responsible for memory management.

char * buffer;

buffer = (char*) malloc(42);

// Do something with buffer

free(buffer);

In the code above, the malloc method is used for applying for memory, you must use the free method to release memory after it is no longer used.

This is cumbersome, so most languages provide automatic memory management to reduce the burden on programmers, which is called “garbage collection” (garbage collector).

The garbage collection mechanism

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

The most commonly used method is called “reference counting”: The language engine has a “reference table” that holds the number of references to all resources in memory (usually various values). If the number of references to an object is 0, it means that the object is no longer used so you can release the memory of this object.

In the figure above, two objects in the lower left corner can be released because there is no reference to them.

If a object is no longer needed but the number of references is not 0, so the garbage collector can not release the memory, which is a memory leak.

const arr = [1, 2, 3, 4];

console.log('hello world');

In the code above, the array [1, 2, 3, 4] is an object that consumes memory. Variable arr is the only reference to this object, so the number of references is 1. Although the following code does not use arr, it continues to consume memory.

If you add a line of code to remove the reference to [1, 2, 3, 4] from the arr, this memory can be freed by the garbage collector.

let arr = [1, 2, 3, 4];

console.log('hello world');

arr = null;

In the code above, the arr is reset to null so that the reference to [1, 2, 3, 4] is lifted, and the number of references becomes 0 so that memory can be released.

So it’s not that there’s a garbage collection mechanism that makes it easier for programmers. You still need to focus on memory consumption: those that take up space, and once they are no longer used, you have to check if there are references to them. If so, you must manually dismiss the reference.

Memory leak Identification method

How can I observe a memory leak?

The rule of thumb is that if the memory is consumed once more than once after five successive garbage collections, there is a memory leak. This requires real-time viewing of memory usage.

browser

Follow these steps to view memory footprint in Chrome.

  • Open Developer Tools, select Performance Panel
  • Check memory in the Capture field at the top
  • Click on the Recording button in the upper left corner.
  • Perform various operations on the page to simulate user usage.
  • After a while, click on the Stop button in the dialog box to display the memory footprint of the time.

If the memory footprint is basically stable, close to the average level, there is no memory leak.

On the contrary, there is a memory leak.

Node.js

We can use process.memoryUsage to measure the memory usage of the Node.js process

For example, the code:

console.log(process.memoryUsage());

Will generate:

{

rss: 4935680,

heapTotal: 1826816,

heapUsed: 650472,

external: 49879

}

process.memoryUsage returns an object that contains memory usage information for the node process. The object contains four fields in bytes, and have the following meanings.

  • RSS (Resident set size): All memory consumption, including instruction area and stack.
  • heapTotal: Total size of the heap.
  • heapUsed: Heap actually used.
  • external: Memory consumed by C + + objects inside the External V8 engine.

Use the heapUsed field to determine if there is a memory leak.

WeakMap

As mentioned earlier, it is very important to clear the reference in time. But you can’t always remember to release the memory manually, sometimes forgetting it by mistake, so there are so many memory leaks.

It is best to have a way to declare which references must be purged manually and which references can be ignored when you create a new reference. When other references disappear, the garbage collection mechanism can release memory. This will greatly reduce the burden of the programmer, you just need to clear the main reference.

ES6 with this in mind, two new data structures have been introduced: WeakSet and WeakMap. Their references to values are not included in the garbage collection mechanism, so there is a “weak” in the name, which means that this is a weak reference.

Take WeakMap as an example to see how it solves the memory leak.

const wm = new WeakMap();

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

wm.set(element, 'some information');

wm.get(element) // "some information"

In the code above, a new WeakMap instance is created, and then a DOM node is stored as a key in the instance, and some additional information is used as the key value in the WeakMap. At this point, the reference to the element in WeakMap is a weak reference and will not be counted into the garbage collection mechanism.

In other words, the reference count for the DOM node object is 1, not 2. At this point, once the reference to the node is eliminated, the memory it consumes will be freed by the garbage collection mechanism. This key-value pair saved by WeakMap will also disappear automatically.

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

WeakMap example

First, open the node command line.

node --expose-gc

The –expose-gc parameter indicates that garbage collection is allowed to be performed manually.

Then execute the following code.

// Perform a garbage collection manually and ensure that the memory usage is accurate

> global.gc();

undefined

// View the initial state of memory consumption, heapUsed is around 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 is still around 4M

> process.memoryUsage();

{ rss: 20537344,

heapTotal: 9474048,

heapUsed: 3967272,

external: 8993 }

// add a new key-value pair in WeakMap

> wm.set(b, new Array(5*1024*1024));

WeakMap {}

// Perform a garbage collection manually

> global.gc();

undefined

// heapUsed is now around 45M

> process.memoryUsage();

{ rss: 62652416,

heapTotal: 51437568,

heapUsed: 45911664,

external: 8951 }

// dereference object b

> b = null;

null

// perform garbage collection again

> global.gc();

undefined

// Now the heapUsed has turned back to about 4M.

> process.memoryUsage();

{ rss: 20639744,

heapTotal: 8425472,

heapUsed: 3979792,

external: 8956 }

In the above code, as long as the external reference disappears, the WeakMap internal reference is automatically garbage collected. This shows that with its help, to eliminate the memory leaks will be much simpler.

(Finish)

Be the first to comment

Leave a Reply

Your email address will not be published.


*