美文网首页ios 开发
JavaScript内存管理

JavaScript内存管理

作者: iOS小洁 | 来源:发表于2023-03-04 11:02 被阅读0次

JS内存回收

JS 有自动垃圾回收机制,就是找出那些不再继续使用的值,然后释放其占用的内存。

垃圾回收算法:

  • 引用计数垃圾收集
  • 标记清楚算法

内存泄露

如果连续五次垃圾回收之后,内存占用一次比一次大,就有内存泄漏。

在 Chrome 浏览器中,我们可以这样查看内存占用情况

  1. 打开页面,右键选择检查,打开开发者工具
  2. 在顶部勾选 Memory
  3. 模拟用户操作,并进行多次内存快照

判定当前是否有内存泄漏:

  1. 多次快照后,比较每次快照中内存的占用情况,如果呈上升趋势,那么可以认为存在内存泄漏
  2. 某次快照后,看当前内存占用的趋势图,如果走势不平稳,呈上升趋势,那么可以认为存在内存泄漏

在 Node环境 查看内存情况

console.log(process.memoryUsage());
// { 
//     rss: 27709440,
//     heapTotal: 5685248,
//     heapUsed: 3449392,
//     external: 8772 
// }

该对象包含四个字段,单位是字节,含义如下:

  • rss(resident set size):所有内存占用,包括指令区和堆栈。
  • heapTotal:"堆"占用的内存,包括用到的和没用到的。
  • heapUsed:用到的堆的部分。
  • external: V8 引擎内部的 C++ 对象占用的内存。

常见内存泄露:

1、非必要的全局变量。如下代码,就是创建了两个全局变量name1,name2

function foo() {
    name1 = 'xyj'; // 没有声明变量 实际上是全局变量 => window.name1
    this.name2 = 'why' // 全局变量 => window.name2
}
foo();

2、被遗忘的定时器和回调函数

var serverData = loadData();
setInterval(function() {
    var renderer = document.getElementById('renderer');
    if(renderer) {
        renderer.innerHTML = JSON.stringify(serverData);
    }
}, 5000); // 每 5 秒调用一次

如果后续 renderer 元素被移除,整个定时器实际上没有任何作用。 但如果你没有回收定时器,整个定时器依然有效, 不但定时器无法被内存回收, 定时器函数中的依赖也无法回收。在这个案例中的 serverData 也无法被回收。

3、闭包

在 JS 开发中,我们会经常用到闭包,一个内部函数,有权访问包含其的外部函数中的变量。 下面这种情况下,闭包也会造成内存泄露:

var theThing = null;
var replaceThing = function () {
  var originalThing = theThing;
  var unused = function () {
    if (originalThing) // 对于 'originalThing'的引用
      console.log("hi");
  };
  theThing = {
    longStr: new Array(1000000).join('*'),
    someMethod: function () {
      console.log("message");
    }
  };
};
setInterval(replaceThing, 1000);

这段代码,每次调用 replaceThing 时,theThing 获得了包含一个巨大的数组和一个对于新闭包 someMethod 的对象。 同时 unused 是一个引用了 originalThing 的闭包。

这个范例的关键在于,闭包之间是共享作用域的,尽管 unused 可能一直没有被调用,但是 someMethod 可能会被调用,就会导致无法对其内存进行回收。 当这段代码被反复执行时,内存会持续增长。

function makeAdder(count) {
  return function (num) {
    return count + num
  }
}

var add5 = makeAdder(5)
console.log(add5(6))

这段代码中makeAdder函数执行完毕,正常情况下我们的AO对象会被释放; 但是因为在0xb00的函数中有作用域引用指向了这个AO对象,所以它不会被释放掉;

解决方案 add5 = null

4、DOM 引用

很多时候, 我们对 Dom 的操作, 会把 Dom 的引用保存在一个数组或者 Map 中。

var elements = {
    image: document.getElementById('image')
};
function doStuff() {
    elements.image.src = 'http://example.com/xxx.png';
}
function removeImage() {
    document.body.removeChild(document.getElementById('image'));
    // 这个时候我们对于 #image 仍然有一个引用, Image 元素, 仍然无法被内存回收.
}
复制代码

上述案例中,即使我们对于 image 元素进行了移除,但是仍然有对 image 元素的引用,依然无法对齐进行内存回收。

另外需要注意的一个点是,对于一个 Dom 树的叶子节点的引用。 举个例子: 如果我们引用了一个表格中的td元素,一旦在 Dom 中删除了整个表格,我们直观的觉得内存回收应该回收除了被引用的 td 外的其他元素。 但是事实上,这个 td 元素是整个表格的一个子元素,并保留对于其父元素的引用。 这就会导致对于整个表格,都无法进行内存回收。所以我们要小心处理对于 Dom 元素的引用。

相关文章

  • JavaScript —— 内存管理及垃圾回收

    目录 JavaScript内存管理内存为什么需要管理?内存管理概念JavaScript中的内存管理JavaScri...

  • 谈谈js中的内存机制——垃圾回收机制

    内存管理机制就是分配内存管理,每种编程语言都有它的内存管理机制,JavaScript的内存管理机制是:内存基元在变...

  • 理解 JavaScript 中的内存管理(Memory Mana

    理解 JavaScript 中的内存管理(Memory Management) 平时写 JavaScript 代码...

  • JavaScript 内存管理

    内存管理 参考 MDN内存管理 生命周期 内存分配 使用内存 不需要时垃圾回收,释放内存 引用计数方式 判断对象有...

  • JavaScript内存管理

    摘抄一篇文章,写得非常好,出处在此作为一门高级语言,JS并不像低级语言C/C++那样拥有对内存的完全掌控。JS中内...

  • JavaScript内存管理

    内存生命周期 不管什么程序语言,内存生命周期基本是一致的:1.分配你所需要的内存2.使用分配到的内存(读、写)3....

  • JavaScript内存管理

    作为一门高级语言,JS并不像低级语言C/C++那样拥有对内存的完全掌控。JS中内存的分配和回收都是自动完成的,内存...

  • javascript内存管理

    内存声明周期 分配你所需要的内存 使用分配的内存(读写) 不再需要时释放内存 内存分配 javascript在声明...

  • JavaScript 内存管理

    简介 像 C 家族语言这样的高级语言一般都有底层的内存管理接口,比如 malloc()和free()。另一方面,J...

  • JavaScript 内存管理

    作为一个 JavaScript 的开发者,大多数情况下你可能不会担心内存管理问题,因为 JavaScript 引擎...

网友评论

    本文标题:JavaScript内存管理

    本文链接:https://www.haomeiwen.com/subject/facyldtx.html