介绍内存泄漏是每个开发者最终都会面临的问题,它是许多问题的根源:卡顿、崩溃、高延迟等应用程序问题。什么是内存泄漏?从本质上讲,内存泄漏可以定义为应用程序不再需要占用由于某种原因未被操作系统或可用内存池回收的内存的时间。编程语言以不同的方式管理内存。只有开发人员知道哪些内存不再需要,操作系统可以回收它。一些编程语言提供的语言特性可以帮助开发人员做这样的事情。其他人则希望开发人员清楚内存的需求。JavaScript内存管理JavaScript是一种垃圾收集语言。垃圾收集语言通过定期检查以前分配的内存是否可达来帮助开发人员管理内存。换句话说,垃圾收集语言缓解了“内存仍然可用”和“内存仍然可达”的问题。两者之间的区别很微妙但很重要:只有开发人员知道哪些内存将来仍会被使用,而无法访问的内存是由算法确定和标记的,并在适当的时候被操作系统回收。JavaScript内存泄漏垃圾收集语言内存泄漏的主要原因是不需要的引用。在理解它之前,有必要了解一下垃圾回收语言是如何区分内存是可达的还是不可达的。Mark-and-sweep大多数垃圾收集语言使用的算法称为Mark-and-sweep。该算法包括以下步骤:垃圾收集器创建一个“根”列表。根通常是对代码中全局变量的引用。在JavaScript中,“window”对象是一个全局变量,被认为是根。窗口对象始终存在,因此垃圾收集器可以检查它及其所有子对象是否存在(即不是垃圾);所有的根都被检查并标记为活动的(即不是垃圾)。还递归检查所有子对象。如果root中的所有对象都可访问,则不认为是垃圾。所有未标记的内存将被视为垃圾,收集器现在可以释放内存并将其返回给操作系统。现代垃圾收集器改进了算法,但本质是一样的:标记可达内存,剩下的进行垃圾收集。不需要的引用是开发人员知道不再需要但由于某种原因仍留在活动根树中的内存引用。在JavaScript中,不需要的引用是保留在代码中的变量,不再需要它,但它指向一块应该释放的内存。有些人认为这是开发人员的错误。为了理解JavaScript中最常见的内存泄漏,我们需要了解什么样的引用容易被遗忘。三种常见的JavaScript内存泄漏1:意外的全局变量JavaScript对未定义变量的处理很松散:未定义变量在全局对象中创建一个新变量。在浏览器中,全局对象是窗口。functionfoo(arg){bar="thisisahiddenglobalvariable";}真相是:functionfoo(arg){window.bar="thisisanexplicitglobalvariable";}functionfoo忘记在里面使用var,不小心创建了一个全局变量。这个例子泄漏了一个简单的字符串,这是无害的,但还有更糟糕的情况。另一个意想不到的全局变量可能是这样创建的:functionfoo(){this.variable="potentialaccidentalglobal";}//Foo调用自身,this指向全局对象(window)//而不是undefinedfoo();在JavaScript文件的头部加上'usestrict'可以避免此类错误。启用JavaScript的严格模式解析以避免意外的全局变量。全局变量注意事项虽然我们讨论了一些意想不到的全局变量,但仍然有一些显式全局变量会产生垃圾。它们被定义为不被收集(除非定义为空或重新分配)。尤其是在使用全局变量来临时存储和处理大量信息时,需要格外小心。如果必须使用全局变量来存储大量数据,请确保将其设置为null或在使用后重新定义它。与全局变量相关的内存消耗增加的主要原因是缓存。缓存数据是为了复用,缓存要有个上限才有用。高内存消耗导致缓存溢出,因为缓存内容无法回收。2:忘记定时器或回调在JavaScript中使用setInterval是很常见的。常见的一段代码:varsomeResource=getData();setInterval(function(){varnode=document.getElementById('Node');if(node){//处理节点和someResourcenode.innerHTML=JSON.stringify(someResource));}},1000);这个例子说明了什么:不再需要与节点或数据关联的计时器,可以删除节点对象,不再需要整个回调函数。但是定时器回调函数还是没有被回收(定时器停止时会被回收)。同时,如果someResource存储了大量数据,则无法回收。对于观察者示例,重要的是在不再需要它们(或关联的对象变得不可访问)时显式删除它们。旧的IE6无法处理循环引用。今天,即使没有明确删除它们,一旦观察者对象变得不可访问,大多数浏览器也会回收观察者处理程序。观察者代码示例:varelement=document.getElementById('button');functiononClick(event){element.innerHTML='text';}element.addEventListener('click',onClick);对象观察器和循环引用注意事项旧版本的IE无法检测DOM节点和JavaScript代码之间的循环引用,这可能导致内存泄漏。如今,现代浏览器(包括IE和MicrosoftEdge)使用更高级的垃圾回收算法,可以正确检测和处理循环引用。也就是说,回收节点内存时,不需要调用removeEventListener。3:DOM之外的引用有时保留DOM节点的内部数据结构很有用。如果要快速更新表的几行,将DOM的每一行存储为字典(JSON键值对)或数组是有意义的。此时,对同一个DOM元素有两个引用:一个在DOM树中,一个在字典中。如果您决定将来删除这些行,则需要清除这两个引用。varelements={button:document.getElementById('button'),image:document.getElementById('image'),text:document.getElementById('text')};functiondoStuff(){image.src='http://some.url/image';button.click();console.log(text.innerHTML);//更多逻辑}functionremoveButton(){//按钮是body的后代元素document.body.removeChild(document.getElementById('button'));//此时,还有一个全局的#button引用//elements字典。按钮元素还在内存中,无法被GC回收。此外,还必须考虑对DOM树中的内部节点或子节点的引用。假设您在JavaScript代码的表中保存了对
- 1华为申请新专利!新款智能手表将内置耳机内存
- 2大内存玩起来很有趣,华为nova3i 6G+128G版本开启
- 3更多内存,更多选择,华为nova3i 6G+128G今日正式
- 4第八代i7+16GB大内存笔记本新兵,加速你的开学速度
- 5企业为何需要内存安全
- 6荣耀平板2发布:3G大内存+4G全网通,体验升级
- 7全国首创! 360加入Ecma,参与JavaScript语言
- 8165Hz高刷新屏,18G内存,内置风扇!腾讯红魔游戏手机6
- 9「轻薄长续航 越级大内存」vivo Y100 正式发布 首销
- 10内存安全领军者「安芯网盾」完成超亿元人民币 A 轮融资
- 11魅族 21 Note 携全新 Flyme AIOS 正式发布
- 12联想新圆梦f618内存最大支持几G?联想新?
- 1316x1 和 8x2 内存条有很大区别吗?
- 14正常的内存使用情况是多少?
- 15苹果手机内存扩容会对手机带来什么影响吗?
- 16哪些手机值得推荐,续航持久、内存大、不卡顿?
- 17您发现的最大的泄漏是什么?
- 18插2根内存条好还是4根好?
- 19双十一电脑内存会降价吗?
- 20内存芯片分布是双面8芯片好还是双面16芯片好?