常见的 JavaScript 内存泄露
Posted ABC袁
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了常见的 JavaScript 内存泄露相关的知识,希望对你有一定的参考价值。
内存泄漏:由于疏忽或错误造成程序未能释放已经不再使用的内存。内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,导致在释放该段内存之前就失去了对该段内存的控制,从而造成了内存的浪费。
1、意外的全局变量
js对未声明变量会在全局最高对象上创建它的引用,(是以属性存在的,而不是变量),如果在游览器上就是window对象,如果在node环境下就是global;如果未声明的变量缓存大量的数据,它可能只有在页面被刷新或者被关闭的时候才会释放内存,这样就造成了内存意外泄漏。如下例子:
function my() { name="my name is tokey" } my() console.log(window)
在控制台可以看到
还有通过this创建意外的全局变量
function my() { this.name="my name is tokey" } my() console.log(window.name) //my name is tokey 此时的this指向的并不是undefined而是全局对象window
针对上面类型的内存泄漏我们在平时一定要声明变量,不要有全局直接引用。(在javascript文件中添加 \'use strict\'
,开启严格模式,可以有效地避免上述问题。)
2、console.log
作为前端平时使用console.log在控制台打出相对应的信息可以说是非常常见。但如果没有去掉console.log可能会存在内存泄漏。因为在代码运行之后需要在开发工具能查看对象信息,所以传递给console.log的对象是不能被垃圾回收。
3、闭包
首先闭包是一个函数A返回一个内联的函数B,及时A函数执行完函数B也可以访问函数A里面的变量,这就是一个简单的闭包。本质上闭包是将函数内部和外部连接起来的一座桥梁。
function my(name) { function sendName() { console.log(name) } return sendName } var test=my("tokey") test() //tokey
在my()内部创建的sendName()函数是不会被回收的,因为它被全局变量test引用,处于随时被调用的状态。如果向释放内存可以设置test=null;由于闭包会携带包含它的函数的作用域,因此会比其他函数占用更多的内存。过度使用闭包可能会导致内存占用过多。
4、DOM泄漏
游览器中DOM和js采用的是不一样的引擎,DOM采用的是渲染引擎,而js采用的是v8引擎,所以在用js操作DOM时会比较耗费性能,因为他们需要桥来链接他们。为了减少DOM的操作,我们一般将常用的DOM。我们会采用变量引用的方式会将其缓存在当前环境。如果在进行一些删除、更新操作之后,可能会忘记释放已经缓存的DOM,话不多说直接来个例子
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="maximum-scale=1.0,minimum-scale=1.0,user-scalable=0,initial-scale=1.0, width=device-width"> <title>Title</title> <style> *{ margin: 0; padding: 0; } </style> </head> <body> <div class="main"> <div class="test">天</div> <div class="item">天</div> <div class="item">向</div> </div> <button id="add">点击我增加</button> <button id="remove">点击我减少</button> </body> <script src="js/Zepto.js"></script> <script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script> <script> var add=document.querySelector("#add"); var remove=document.querySelector("#remove"); var main=document.querySelector(".main") var test=document.querySelector(".test") add.onclick=function () { var itemN=document.createElement(\'div\') var txt=document.createTextNode(\'上\') itemN.appendChild(txt) main.appendChild(itemN) } remove.onclick=function () { main.removeChild(test) } </script> </html>
通过chrome游览器的内存调试工作我们可以看到
在我点击了三次增加之后,可以明显的看到节点(绿线)有三次明显的增加,之后我又删除了一个节点,但绿线没有下降,这是为什么呢?,这也就是内存泄漏。原因就是删除的DOM在js中有全局的引用。也就是我删除的test在文中被引用,所以无法释放内存。所以在删除更新等操作后应该将其设置为null。
5、被遗忘的timers
js中常用的定时器setInterval()、setTimeout().他们都是规定延迟一定的时间执行某个代码,而其中setInterval()和链式setTimeout()在使用完之后如果没有手动关闭,会一直存在执行占用内存,所以在不用的时候我们可以通过clearInterval()、clearTimeout() 来关闭其对应的定时器,释放内存。熟悉朋友都知道这类定时器是有误差的,所以游览器给出了专门的API-requestAnimationFrame();大家可以试一下。
以上是关于常见的 JavaScript 内存泄露的主要内容,如果未能解决你的问题,请参考以下文章