摘要:閉包的本質是將函數內部和函數外部連接起來的一座橋梁。這就可能造成大量內存得不到回收內存泄露,因為它們的引用次數永遠不可能是。早期的版本里采用是計數的垃圾回收機制,閉包導致內存泄露的一個原因就是這個算法的一個缺陷。
1.閉包的概念
閉包:指有權訪問另一個函數作用域中的變量的函數。
閉包的本質是將函數內部和函數外部連接起來的一座橋梁。
例1:
function outer(){ var a=1; function inner(){ a++; alert(a); } return inner; } var f1=outer();//創建了一個閉包,f1能訪問outer函數中的變量 f1();//彈出2.
這段代碼的特點在于:
1.函數inner嵌套在函數outer內部
2.函數outer返回函數inner,并將值賦給了f1
例2:
// 實現累加:方式1 var a = 0; var add = function(){ a++; console.log(a) } add(); add(); //方式2 :閉包 var add = (function(){ var a = 0; return function(){ a++; console.log(a); } })(); console.log(a); //undefined add(); add(); //方式2的優點:減少全局變量,將變量私有化3.閉包與變量的關系
閉包只能取得包含函數中任何變量的最后一個值。
例:
function f1() { var res = new Array(); for(var i=0;i<10;i++){ res[i] = function() { alert(i); }; } return res; } var f2 = f1(); var f2 = f1(); f2[0]();//alert 10 //并不會返回一次彈出0-9的函數數組,而是彈出10個10的函數數組,因為res中每個函數的作用域中都保存著f1()的活動對象,引用的是同一個變量i,當f1()返回后i的值為10
解決方法:
function f1() { var res = new Array(); for(var i=0;i<10;i++){ res[i] = (function(num) { return function (){ alert(num); } })(i);//函數參數按值傳遞 } return res; } var f2 = f1(); var f2 = f1(); f2[0]();//alert 04.內存泄露及解決方案
垃圾回收機制
說到內存管理,自然離不開JS中的垃圾回收機制,有兩種策略來實現垃圾回收:標記清除 和 引用計數;
標記清除:垃圾收集器在運行的時候會給存儲在內存中的所有變量都加上標記,然后,它會去掉環境中的變量的標記和被環境中的變量引用的變量的標記,此后,如果變量再被標記則表示此變量準備被刪除。 2008年為止,IE,Firefox,opera,chrome,Safari的javascript都用使用了該方式;
引用計數:跟蹤記錄每個值被引用的次數,當聲明一個變量并將一個引用類型的值賦給該變量時,這個值的引用次數就是1,如果這個值再被賦值給另一個變量,則引用次數加1。相反,如果一個變量脫離了該值的引用,則該值引用次數減1,當次數為0時,就會等待垃圾收集器的回收。
這個方式存在一個比較大的問題就是循環引用,就是說A對象包含一個指向B的指針,對象B也包含一個指向A的引用。 這就可能造成大量內存得不到回收(內存泄露),因為它們的引用次數永遠不可能是 0 。早期的IE版本里(ie4-ie6)采用是計數的垃圾回收機制,閉包導致內存泄露的一個原因就是這個算法的一個缺陷。
我們知道,IE中有一部分對象并不是原生額javascript對象,例如,BOM和DOM中的對象就是以COM對象的形式實現的,而COM對象的垃圾回收機制采用的就是引用計數。因此,雖然IE的javascript引擎采用的是標記清除策略,但是訪問COM對象依然是基于引用計數的,因此只要在IE中設計COM對象就會存在循環引用的問題!
例子:
window.onload = function(){ var ele = document.getElementById("id"); ele.onclick = function(){ alert(ele.id); } }
這段代碼為什么會造成內存泄露?
ele.onclick = function(){ alert(ele.id); }
執行這段代碼的時候,將匿名函數對象賦值給ele的onclick屬性;然后匿名函數內部又引用了ele對象,存在循環引用,所以不能被回收。
解決方法:
window.onload = function(){ var ele = document.getElementById("id"); var id = ele.id; //解除循環引用 ele.onclick = function(){ alert(id); } ele = null; // 將閉包引用的外部函數中活動對象清除 }5.總結閉包的優缺點
優點:
當需要一個變量常駐內存時,閉包可以實現一個變量常駐內存 (如果多了就占用內存了)
避免全局變量的污染
私有化變量
缺點:
因為閉包會攜帶包含它的函數的作用域,因此會比其他函數占用更多的內存
引起內存泄露
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/79029.html
摘要:解決方式是,當我們不使用它們的時候,手動切斷鏈接淘汰把和對象轉為了真正的對象,避免了使用這種垃圾收集策略,消除了以下常見的內存泄漏的主要原因。以上參考資料高程垃圾收集類內存泄漏及如何避免內存泄露及解決方案詳解類內存泄漏及如何避免 showImg(http://ww1.sinaimg.cn/large/005Y4rCogy1ft1ikzcqzqj30ka0et77a.jpg); 前言 起...
摘要:垃圾回收內存管理實踐先通過一個來看看在中進行垃圾回收的過程是怎樣的內存泄漏識別在環境里提供了方法用來查看當前進程內存使用情況,單位為字節中保存的進程占用的內存部分,包括代碼本身棧堆。 showImg(https://segmentfault.com/img/remote/1460000019894672?w=640&h=426);作者 | 五月君Node.js 技術棧 | https:...
摘要:的內存泄漏對于這門語言的使用者來說,大多數的使用者的內存管理意識都不強。內存泄漏的定義指由于疏忽或錯誤造成程序未能釋放已經不再使用的內存的情況。 javascript的內存泄漏 對于JavaScript這門語言的使用者來說,大多數的使用者的內存管理意識都不強。因為JavaScript一直以來都只作為在網頁上使用的腳本語言,而網頁往往都不會長時間的運行,所以使用者對JavaScript的...
摘要:介紹瀏覽器的具有自動垃圾回收機制,也就是說,執行環境會負責管理代碼執行過程中使用的內存。中的內存泄漏問題程序的內存溢出后,會使某一段函數體永遠失效取決于當時的代碼運行到哪一個函數,通常表現為程序突然卡死或程序出現異常。 showImg(https://segmentfault.com/img/remote/1460000018932880?w=4400&h=3080); 1. 介紹 瀏...
摘要:引擎對堆內存中的對象進行分代管理新生代存活周期較短的對象,如臨時變量字符串等。內存泄漏對于持續運行的服務進程,必須及時釋放不再用到的內存。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周正式開始前端進階的第一期,本周的主題是調用堆棧,今天是第4天。 本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了解本進階計劃...
閱讀 2441·2021-11-23 09:51
閱讀 1867·2021-10-13 09:40
閱讀 1372·2021-09-30 10:01
閱讀 590·2021-09-26 09:46
閱讀 2234·2021-09-23 11:55
閱讀 1385·2021-09-10 10:51
閱讀 2240·2021-09-09 09:33
閱讀 2228·2019-08-29 17:25