该对象包含四个字段,单位是字节,含义如下:
- rss(resident set size):所有内存占用,包括指令区和堆栈。
- heapTotal:"堆"占用的内存,包括用到的和没用到的。
- heapUsed:用到的堆的部分。
- external: V8 引擎内部的 C++ 对象占用的内存。
判断内存泄漏,以heapUsed字段为准。
常见的内存泄露案例
意外的全局变量
- function foo() {
- bar1 = 'some text'; // 没有声明变量 实际上是全局变量 => window.bar1
- this.bar2 = 'some text' // 全局变量 => window.bar2
- }
- foo();
在这个例子中,意外的创建了两个全局变量 bar1 和 bar2
被遗忘的定时器和回调函数
在很多库中, 如果使用了观察者模式, 都会提供回调方法, 来调用一些回调函数。
要记得回收这些回调函数。举一个 setInterval的例子:
- var serverData = loadData();
- setInterval(function() {
- var renderer = document.getElementById('renderer');
- if(renderer) {
- renderer.innerHTML = JSON.stringify(serverData);
- }
- }, 5000); // 每 5 秒调用一次
如果后续 renderer 元素被移除,整个定时器实际上没有任何作用。
但如果你没有回收定时器,整个定时器依然有效, 不但定时器无法被内存回收,
定时器函数中的依赖也无法回收。在这个案例中的 serverData 也无法被回收。
闭包
在 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 可能会被调用,就会导致无法对其内存进行回收。
当这段代码被反复执行时,内存会持续增长。
DOM 引用
很多时候, 我们对 Dom 的操作, 会把 Dom 的引用保存在一个数组或者 Map 中。
- var elements = {
- image: document.getElementById('image')
- };
- function doStuff() {
- elements.image.src = 'http://example.com/image_name.png';
- }
- function removeImage() {
- document.body.removeChild(document.getElementById('image'));
- // 这个时候我们对于 #image 仍然有一个引用, Image 元素, 仍然无法被内存回收.
- }
上述案例中,即使我们对于 image 元素进行了移除,但是仍然有对 image 元素的引用,依然无法对齐进行内存回收。
另外需要注意的一个点是,对于一个 Dom 树的叶子节点的引用。
举个例子: 如果我们引用了一个表格中的td元素,一旦在 Dom 中删除了整个表格,我们直观的觉得内存回收应该回收除了被引用的 td 外的其他元素。
但是事实上,这个 td 元素是整个表格的一个子元素,并保留对于其父元素的引用。
这就会导致对于整个表格,都无法进行内存回收。所以我们要小心处理对于 Dom 元素的引用。
如何避免内存泄漏
记住一个原则:不用的东西,及时归还。
- 减少不必要的全局变量,使用严格模式避免意外创建全局变量。
- 在你使用完数据后,及时解除引用(闭包中的变量,dom引用,定时器清除)。
- 组织好你的逻辑,避免死循环等造成浏览器卡顿,崩溃的问题。
(编辑:温州站长网)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|