阅读 266

浅谈JavaScript 中释放内存(js中哪些操作会造成内存泄露)

JavaScript 中释放内存的方式

JavaScript 采用引用计数的方式来动态管理内存。

什么是引用计数呢?举例如下:

// 创建了一个 obj 对象,动态分配了一些内存 【obj 引用计数为 0】
let obj = { value: 'XXXXX' };

// data1 引用了 obj,【obj 引用计数变为 1】
let data1 = { value: obj }
// data2 引用了 obj,【obj 引用计数变为 2】
let data2 = { value: obj }

// data1 释放对 obj 的引用,【obj 引用计数变为 1】
data1.value = undefined;
// data2 释放对 obj 的引用,【obj 引用计数变为 0】
delete data2.value;

// 假设后续代码再无对 obj 的引用
// 此时 obj 引用计数为 0,当 GC 发生时,obj 的内存将会被回收复制代码

简单来说,JavaScript 引擎在运行时统计一块内存被引用的次数,并定期进行垃圾回收(GC)。如果一块堆内存的引用次数变为 0,则会在后续的 GC 中被回收,也就是我们常说的这块内存被释放了。

所以当一个 JavaScript 中的变量确定不会再被使用之后,我们可以手动解除对它的引用,以便能够释放内存。通常,解除引用的方式有几种:

  • 设为 undefined,例如 data.value = undefined

  • 设为 null,例如 data.value = null

  • delete,例如 delete data.value

它们的性能差异如何呢?

实验过程

delete

先来看看 delete 的性能表现。

正向 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`);
})()复制代码

运行结果

avg 67.5ms in 10 times复制代码

反向 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`);
})()复制代码

结果

avg 64.4ms in 10 times复制代码

设为 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`);
})()复制代码

运行结果

avg 0.8ms in 10 times复制代码

设为 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`);
})()复制代码

运行结果

avg 0.8ms in 10 times复制代码

结论

  • 通过设为 undefined 或 null 来解引用,比 delete 快近 70 倍

  • 没有看出明显的内存差异。

所以,在性能敏感的场景解引用,通过赋值为 undefined 或 null 性能更佳。


作者:nelyo
链接:https://juejin.cn/post/7031091616957857829


文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐