本文转载自微信公众号《Android开发编程》,作者Android开发编程。转载本文请联系Android开发编程公众号。前言JS自带一套内存管理引擎,负责创建对象、销毁对象和垃圾回收。让我们讨论一下垃圾收集机制和内存泄漏;一、垃圾回收机制详解1、什么是js回收机制?垃圾回收机制的原理是找到不再使用的变量,释放它们的内存。垃圾收集器会按照固定的时间间隔(或者代码中预定的收集时间)周期性的执行这个操作;Javascript会找出不再使用的变量,不再使用意味着这个变量生命周期的结束。Javascript中有两种变量——全局变量和局部变量。所有变量的声明循环将一直持续到页面被卸载;而局部变量是在函数中声明的,它们的声明周期从函数执行开始,直到函数执行结束。在这个过程中,局部变量会在堆或栈上分配相应的空间来存储它们的值。函数执行结束后,这些局部变量将不再使用,它??们占用的空间将被释放;garbagecollection两种实现方式:标记清除,引用计数2、标记清除(浏览器主流做法)主要思想是标记当前没有被使用的值,然后回收其内存;垃圾收集器会对存储在内存中的变量进行标记,然后他会清除环境变量和环境变量引用的变量。之后,被标记的变量(环境变量中不访问的变量)就是要删除的变量;finallygarbagecollection清理器完成清理工作,销毁那些标记的值,回收它们占用的内存空间;markandscan算法经过:根节点:一般来说,根是代码中引用的一个全局变量;然后算法检查所有根节点和它们并将它们标记为活动的(意味着它们不是垃圾)。任何不能被根节点访问的变量都会被标记为垃圾;最后,垃圾收集器释放所有未标记为活动的内存块,并将这些内存块返回给操作系统;3.引用计数(IE9以下)表示跟踪记录所有值被引用的次数;比如变量a赋值后,这个值的引用次数为1,将a的值赋给另一个变量b,则引用次数+1;但是当b被赋另一个值时,引用数-1;当该值的参考书为0时,表示没有办法访问这个值,此时可以回收内存。IE9以下仍然使用引用计数。当一个对象被循环引用时,引用次数不能标记为0,这样会导致它无法被回收。对于其他浏览器已过时;下面的代码varo1={o2:{x:1}};//创建了两个对象。//'o1'对象引用'o2'对象作为其属性。//不能被垃圾回收varo3=o1;//'o3'变量是引用'o1'指向的对象的第二个变量。o1=1;//现在,'o1'中的对象只有一个引用,由'o3'变量表示varo4=o3.o2;//对对象'o2'属性的引用。//这个对象现在有两个引用:一个作为属性,另一个作为'o4'变量o3='374';//原来在"o1"中的对象现在是nil,对它的引用可以被垃圾回收。//然而,它的'o2'属性存在,被'o4'变量引用,所以它不能被释放。o4=null;//'o1'中原始对象的'o2'属性对它的引用为零。它可以被垃圾收集。2.Js中常见的内存泄漏内存泄漏是应用程序过去使用过但不再需要的内存碎片,还没有归还给操作系统或可用内存池。因为没有发布,可能导致程序卡死、崩溃;1.意外的全局变量functionfoo(arg){bar="test";//window.bar="test";}js没有配对声明一个变量会在最高的全局对象(作为属性存在,不是变量)。如果在浏览器上是window对象,在node环境下就是全局的;如果一个未声明的变量缓存了大量的Data,它可能只有在页面刷新或关闭时才释放内存,这会导致意外的内存泄漏;2.被遗忘的定时器或回调函数我们以JavaScript中经常使用的setInterval为例;varserverData=loadData();setInterval(function(){varrenderer=document.getElementById('renderer');if(renderer){renderer.innerHTML=JSON.stringify(serverData);}},5000);//每5执行一次秒一次。上面的代码片段显示了使用计时器引用节点或无用数据的后果。它既不被收集也不被释放。无法被垃圾回收器回收,调用频繁,占用内存;而正确的使用方式是确保一旦依赖于它们的事件处理完毕,通过显式调用将它们删除;3、闭包闭包是一个函数A返回一个内联函数B,即使函数A执行完函数B后,它也可以访问函数A中的变量,是一个简单的闭包;本质上,闭包是连接函数内外的桥梁;functionmy(name){functionsendName(){console.log(name)}returnsendName}vartest=my("test")test()//test在my()内部创建的sendName()函数不会被回收,因为它是被全局变量test引用,处于随时被调用的状态。如果要释放内存,可以设置test=null;由于闭包将承载包含它的函数的范围,因此它将比其他函数占用更多的内存。过多使用闭包可能会导致内存占用过大4.DOM泄漏DOM和js在浏览器中使用不同的引擎,DOM使用的是渲染引擎,而js使用的是v8引擎,所以使用js操作DOM可以更加耗费性能,因为它们需要一座桥来连接它们。为了减少对DOM的操作,我们一般使用常用的DOM;我们将使用变量引用将其缓存在当前环境中。如果在一些删除和更新操作后忘记释放缓存的DOM;varelements={button:document.getElementById('button'),image:document.getElementById('image')};functiondoStuff(){elements.image.src='http://test.png';}functionremoveImage(){//image元素是body的直接子元素。document.body.removeChild(document.getElementById('image'));//我们仍然可以引用全局元素对象中的按钮。也就是说,按钮元素还在内存中,无法被GC回收}总结GC机制是自动完成的,但我们可以强制启动或关闭它;开发中一定要注意内存泄漏,否则会出现意想不到的情况;一起学习,一起加油;
