摘要:前言在談內(nèi)存泄漏這個(gè)問題之前先看看的垃圾收集機(jī)制,具有自動(dòng)垃圾收集機(jī)制,就是找出那些不再繼續(xù)使用的變量,然后釋放其占用的內(nèi)存。閉包不會(huì)引起內(nèi)存泄漏由于之前的版本對(duì)對(duì)象和對(duì)象使用不同的垃圾收集。因此閉包在的這些版本中會(huì)導(dǎo)致一些特殊的問題。
前言
在談內(nèi)存泄漏這個(gè)問題之前先看看JavaScript的垃圾收集機(jī)制,JavaScript 具有自動(dòng)垃圾收集機(jī)制,就是找出那些不再繼續(xù)使用的變量,然后釋放其占用的內(nèi)存。為此,垃圾收集器會(huì)按照固定的時(shí)間間隔(或代碼執(zhí)行中預(yù)定的收集時(shí)間)。常用的的方法有兩種,即標(biāo)記清楚和引用計(jì)數(shù)。
1. 標(biāo)記清除
JavaScript 中最常用的垃圾收集方式是標(biāo)記清除(mark-and-sweep)。垃圾收集器在運(yùn)行的時(shí)候會(huì)給存儲(chǔ)在內(nèi)存中的所有變量都加上標(biāo)記(可以使用任何標(biāo)記方式)。然后,它會(huì)去掉環(huán)境中的變量以及被環(huán)境中的變量引用的變量的標(biāo)記。而在此之后再被加上標(biāo)記的變量將被視為準(zhǔn)備刪除的變量,原因是環(huán)境中的變量已經(jīng)無法訪問到這些變量了。最后,垃圾收集器完成內(nèi)存清除工作,銷毀那些帶標(biāo)記的值并回收它們所占用的內(nèi)存空間。
1. 引用計(jì)數(shù)
引用計(jì)數(shù)(reference counting)的含義是跟蹤記錄每個(gè)值被引用的次數(shù)。當(dāng)聲明了一個(gè)變量并將一個(gè)引用類型值賦給該變量時(shí),則這個(gè)值的引用次數(shù)就是1。如果同一個(gè)值又被賦給另一個(gè)變量,則該值的引用次數(shù)加1。相反,如果包含對(duì)這個(gè)值引用的變量又取得了另外一個(gè)值,則這個(gè)值的引用次數(shù)減1。當(dāng)這個(gè)值的引用次數(shù)變成0 時(shí),則說明沒有辦法再訪問這個(gè)值了,因而就可以將其占用的內(nèi)存空間回收回來。這樣,當(dāng)垃圾收集器下次再運(yùn)行時(shí),它就會(huì)釋放那些引用次數(shù)為零的值所占用的內(nèi)存。
Netscape Navigator 3.0 是最早使用引用計(jì)數(shù)策略的瀏覽器,但很快它就遇到了一個(gè)嚴(yán)重的問題,請(qǐng)看下面這個(gè)例子:
function problem(){ var objectA = new Object(); var objectB = new Object(); objectA.someOtherObject = objectB; objectB.anotherObject = objectA; }
說明:objectA 和objectB 通過各自的屬性相互引用,即這兩個(gè)對(duì)象的引用次數(shù)都是2,在采用標(biāo)記清除策略的實(shí)現(xiàn)中,由于函數(shù)執(zhí)行之后,這兩個(gè)對(duì)象都離開了作用域,因此這種相互引用不是個(gè)問題。但在采用引用計(jì)數(shù)策略的實(shí)現(xiàn)中,當(dāng)函數(shù)執(zhí)行完畢后,objectA 和objectB 還說明將繼續(xù)存在,因?yàn)樗鼈兊囊么螖?shù)永遠(yuǎn)不會(huì)是0。假如這個(gè)函數(shù)被重復(fù)多次調(diào)用,就會(huì)導(dǎo)致大量內(nèi)存得不到回收。
為此,Netscape 在Navigator 4.0 中放棄了引用計(jì)數(shù)方式,然而引用計(jì)數(shù)導(dǎo)致的麻煩并未就此了結(jié)。IE9以前中有一部分對(duì)象并不是原生JavaScript 對(duì)象。例如,其BOM 和DOM 中的對(duì)象就是使用C++以COM(Component Object Model,組件對(duì)象模型)對(duì)象的形式實(shí)現(xiàn)的,而COM 對(duì)象的垃圾收集機(jī)制采用的就是引用計(jì)數(shù)策略。因此,即使IE 的JavaScript 引擎是使用標(biāo)記清除策略來實(shí)現(xiàn)的,但JavaScript 訪問的COM 對(duì)象依然是基于引用計(jì)數(shù)策略的。換句話說,只要在IE 中涉及COM 對(duì)象,就會(huì)存在循環(huán)引用的問題。
比如:
var element = document.getElementById("some_element"); var myObject = new Object(); myObject.element = element; element.someObject = myObject;
DOM 元素(element)與一個(gè)原生JavaScript 對(duì)象(myObject)之間創(chuàng)建了循環(huán)引用。其中,變量myObject 有一個(gè)名為element 的屬性指向element 對(duì)象;而變量element 也有一個(gè)屬性名叫someObject 回指myObject。由于存在這個(gè)循環(huán)引用,即使將例子中的DOM 從頁面中移除,它也永遠(yuǎn)不會(huì)被回收。
解決辦法:將變量設(shè)為null從而切斷變量與它此前引用的值之間的連接。
myObject.element = null; element.someObject = null;
看完上面的內(nèi)容,我來談?wù)}。
閉包不會(huì)引起內(nèi)存泄漏由于IE9 之前的版本對(duì)JScript 對(duì)象和COM 對(duì)象使用不同的垃圾收集。因此閉包在IE 的這些版本中會(huì)導(dǎo)致一些特殊的問題。具體來說,如果閉包的作用域鏈中保存著一個(gè)HTML 元素,那么就意味著該元素將無法被銷毀
請(qǐng)看例子:
function assignHandler(){ var element = document.getElementById("someElement"); element.onclick = function(){ alert(element.id); }; }
以上代碼創(chuàng)建了一個(gè)作為element 元素事件處理程序的閉包,而這個(gè)閉包則又創(chuàng)建了一個(gè)循環(huán)引用。由于匿名函數(shù)保存了一個(gè)對(duì)assignHandler()的活動(dòng)對(duì)象的引用,因此就會(huì)導(dǎo)致無法減少element 的引用數(shù)。只要匿名函數(shù)存在,element 的引用數(shù)至少也是1,因此它所占用的內(nèi)存就永遠(yuǎn)不會(huì)被回收
解決辦法前言已經(jīng)提到過,把element.id 的一個(gè)副本保存在一個(gè)變量中,從而消除閉包中該變量的循環(huán)引用同時(shí)將element變量設(shè)為null。
function assignHandler(){ var element = document.getElementById("someElement"); var id = element.id; element.onclick = function(){ alert(id); }; element = null; }
總結(jié):閉包并不會(huì)引起內(nèi)存泄漏,只是由于IE9之前的版本對(duì)JScript對(duì)象和COM對(duì)象使用不同的垃圾收集,從而導(dǎo)致內(nèi)存無法進(jìn)行回收,這是IE的問題,所以閉包和內(nèi)存泄漏沒半毛錢關(guān)系。
這篇文章里做了詳細(xì)的測試,有興趣的可以點(diǎn)擊查看
小小插曲:發(fā)個(gè)群鏈接,有興趣的可以加入交流,群號(hào):519875573
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/91124.html
摘要:解決方式是,當(dāng)我們不使用它們的時(shí)候,手動(dòng)切斷鏈接淘汰把和對(duì)象轉(zhuǎn)為了真正的對(duì)象,避免了使用這種垃圾收集策略,消除了以下常見的內(nèi)存泄漏的主要原因。以上參考資料高程垃圾收集類內(nèi)存泄漏及如何避免內(nèi)存泄露及解決方案詳解類內(nèi)存泄漏及如何避免 showImg(http://ww1.sinaimg.cn/large/005Y4rCogy1ft1ikzcqzqj30ka0et77a.jpg); 前言 起...
摘要:就會(huì)造成內(nèi)存泄漏這里導(dǎo)致一直存在內(nèi)存中應(yīng)該將解除引用來避免內(nèi)存泄漏這里導(dǎo)致一致存在內(nèi)存中的垃圾回收機(jī)制看完內(nèi)存泄漏需要了解下的垃圾回收機(jī)制,首先具有自動(dòng)垃圾回收機(jī)制,會(huì)找出不再使用的變量,然后釋放其占用的內(nèi)存。 由閉包引出的垃圾回收 閉包的特性 函數(shù)嵌套函數(shù) 函數(shù)內(nèi)部可以引用外部的參數(shù)和變量 參數(shù)和變量不會(huì)被垃圾回收機(jī)制回收 閉包的定義 閉包 是指有權(quán)訪問另一個(gè)函數(shù)作用域中的變量的...
摘要:積少成多,最后造成內(nèi)存泄漏。前端內(nèi)存泄漏的影響,都是發(fā)生在客戶機(jī)器上,而且基本上現(xiàn)代瀏覽器也會(huì)做好保護(hù)機(jī)制,一般自行刷新之后都會(huì)解決。但是,一旦后端繪制內(nèi)存泄漏造成宕機(jī)之后,整個(gè)服務(wù)器都會(huì)受影響,危險(xiǎn)性更大,搞不好年終獎(jiǎng)就沒了。 引言 Memory Leak 是最難排查調(diào)試的 Bug 種類之一,因?yàn)閮?nèi)存泄漏是個(gè) undecidable problem,只有開發(fā)者才能明確一塊內(nèi)存是不是需...
摘要:的內(nèi)存泄漏對(duì)于這門語言的使用者來說,大多數(shù)的使用者的內(nèi)存管理意識(shí)都不強(qiáng)。內(nèi)存泄漏的定義指由于疏忽或錯(cuò)誤造成程序未能釋放已經(jīng)不再使用的內(nèi)存的情況。 javascript的內(nèi)存泄漏 對(duì)于JavaScript這門語言的使用者來說,大多數(shù)的使用者的內(nèi)存管理意識(shí)都不強(qiáng)。因?yàn)镴avaScript一直以來都只作為在網(wǎng)頁上使用的腳本語言,而網(wǎng)頁往往都不會(huì)長時(shí)間的運(yùn)行,所以使用者對(duì)JavaScript的...
摘要:垃圾回收內(nèi)存管理實(shí)踐先通過一個(gè)來看看在中進(jìn)行垃圾回收的過程是怎樣的內(nèi)存泄漏識(shí)別在環(huán)境里提供了方法用來查看當(dāng)前進(jìn)程內(nèi)存使用情況,單位為字節(jié)中保存的進(jìn)程占用的內(nèi)存部分,包括代碼本身?xiàng)6选? showImg(https://segmentfault.com/img/remote/1460000019894672?w=640&h=426);作者 | 五月君Node.js 技術(shù)棧 | https:...
閱讀 1945·2021-10-11 10:59
閱讀 1050·2021-09-07 09:59
閱讀 2246·2021-08-27 16:17
閱讀 2802·2019-08-30 15:54
閱讀 2287·2019-08-30 12:58
閱讀 1791·2019-08-30 12:53
閱讀 1482·2019-08-28 18:13
閱讀 742·2019-08-26 13:35