“This article has participated in the call for good writing activities, click to view: the back end, the big front end double track submission, 20,000 yuan prize pool waiting for you to challenge!”

Free up memory in JavaScript

JavaScript uses reference counting to manage memory dynamically.

What is reference counting? Examples are as follows:

// create an obj object and allocate some memory dynamically.
let obj = { value: 'XXXXX' };

// data1 references obj, obj reference count changes to 1
let data1 = { value: obj }
// data2 references obj.
let data2 = { value: obj }

// data1 releases the reference to obj.
data1.value = undefined;
// data2 releases the reference to obj.
delete data2.value;

// Assume no further references to obj
// The obj reference count is 0, and when GC occurs, obj's memory will be reclaimed
Copy the code

In simple terms, the JavaScript engine counts the number of times a block of memory is referenced at run time and periodically performs garbage collection (GC). If a block of heap memory has zero references, it will be reclaimed in subsequent GC, which is called the block freed.

So when a JavaScript variable is determined not to be used again, we can manually dereference it to free up memory. In general, there are several ways to dereference:

  • Set to undefined, e.g.data.value = undefined
  • Set to null, e.g.data.value = null
  • delete, e.g.delete data.value

How do they differ in performance?

The experimental process

delete

Let’s take a look at delete’s performance.

To delete

(()=>{ let totalTime = 0, N=10; for(let n=0; n<N; ++n){ let a = {}; for(let i=0; i<1000000; ++i){ a[i] = i; } let startTime = Date.now(); for(let i=0; i<1000000; ++i){ delete a[i]; } totalTime += Date.now() - startTime; a; } console.log(`avg ${totalTime/N}ms in ${N} times`); }) ()Copy the code

The results

Avg 67.5ms in 10 timesCopy the code

Reverse the delete

(()=>{ let totalTime = 0, N=10; for(let n=0; n<N; ++n){ let a = {}; for(let i=0; i<1000000; ++i){ a[i] = i; } let startTime = Date.now(); for(let i=1000000-1; i>-1; --i){ delete a[i]; } totalTime += Date.now() - startTime; a; } console.log(`avg ${totalTime/N}ms in ${N} times`); }) ()Copy the code

The results of

Avg 64.4ms in 10 timesCopy the code

Set to undefined

(()=>{ let totalTime = 0, N=10; for(let n=0; n<N; ++n){ let a = {}; for(let i=0; i<1000000; ++i){ a[i] = i; } let startTime = Date.now(); for(let i=0; i<1000000; ++i){ a[i] = undefined; } totalTime += Date.now() - startTime; a; } console.log(`avg ${totalTime/N}ms in ${N} times`); }) ()Copy the code

The results

Avg 0.8ms in 10 timesCopy the code

Set to null

(()=>{ let totalTime = 0, N=10; for(let n=0; n<N; ++n){ let a = {}; for(let i=0; i<1000000; ++i){ a[i] = i; } let startTime = Date.now(); for(let i=0; i<1000000; ++i){ a[i] = null; } totalTime += Date.now() - startTime; a; } console.log(`avg ${totalTime/N}ms in ${N} times`); }) ()Copy the code

The results

Avg 0.8ms in 10 timesCopy the code

conclusion

  • Through the set toundefinednullTo dereferencedelete Nearly 70 times faster
  • No significant memory differences were observed.

Therefore, dereferencing in performance-sensitive scenarios is better by assigning the value to undefined or null.

(End of text)


If you’re interested in full-stack development with TypeScript, consider TSRPC, the only open source TypeScript RPC framework in the world that supports runtime automatic detection and binary serialization of TypeScript complex types.

GitHub:github.com/k8w/tsrpc Chinese document: TSRPC. Cn video tutorial: www.bilibili.com/video/BV1hM…