首頁 web前端 js教程 閉包會造成記憶體洩漏嗎?

閉包會造成記憶體洩漏嗎?

Nov 01, 2016 am 11:37 AM

前言

在談內存洩漏這個問題之前先看看JavaScript的垃圾收集機制,JavaScript 具有自動垃圾收集機制,就是找出那些不再繼續使用的變量,然後釋放其佔用的內存。為此,垃圾收集器會依照固定的時間間隔(或代碼執行中預定的收集時間)。常用的方法有兩種,即標記清楚和引用計數。

1. 標記清除

JavaScript 中最常用的垃圾收集方式是標記清除(mark-and-sweep)。垃圾收集器在運作的時候會為儲存在記憶體中的所有變數都加上標記(可以使用任何標記方式)。然後,它會去掉環境中的變數以及被環境中的變數所引用的變數的標記。而在此之後再被加上標記的變數將被視為準備刪除的變量,原因是環境中的變數已經無法存取這些變數了。最後,垃圾收集器完成記憶體清除工作,銷毀那些標記的值並回收它們所佔用的記憶體空間。

2. 引用計數

引用計數(reference counting)的意思是追蹤記錄每個值被引用的次數。當宣告了一個變數並將一個引用型別值賦給該變數時,則這個值的參考次數就是1。如果同一個值又被賦給另一個變量,則該值的引用次數加1。相反,如果包含這個值所引用的變數又取得了另一個值,則這個值的引用次數會減1。當這個值的引用次數變成0 時,則表示沒有辦法再存取這個值了,因而就可以將其佔用的記憶體空間回收回來。這樣,當垃圾收集器下次再運行時,它就會釋放那些引用次數為零的值所佔用的記憶體。

Netscape Navigator 3.0 是最早使用引用計數策略的瀏覽器,但很快它就遇到了一個嚴重的問題,請看下面這個例子:

function problem(){ 
    var objectA = new Object(); 
    var objectB = new Object(); 
    objectA.someOtherObject = objectB; 
    objectB.anotherObject = objectA; 
}
登入後複製

說明:objectA 和objectB 透過各自的屬性相互引用,即這兩個物件的引用次數都是2,在採用標記清除策略的實作中,由於函數執行之後,這兩個物件都離開了作用域,因此這種相互引用不是個問題。但在採用引用計數策略的實作中,當函數執行完畢後,objectA 和objectB 也說明將繼續存在,因為它們的引用次數永遠不會是0。假如這個函數重複多次調用,就會導致大量記憶體無法回收。

為此,Netscape 在Navigator 4.0 中放棄了引用計數方式,然而引用計數導致的麻煩並未就此了結。 IE9以前中有一部分物件並不是原生JavaScript 物件。例如,其BOM 和DOM 中的物件就是使用C++以COM(Component Object Model,元件物件模型)物件的形式實現的,而COM 物件的垃圾收集機制所採用的就是引用計數策略。因此,即使IE 的JavaScript 引擎是使用標記清除策略來實現的,但JavaScript 存取的COM 物件仍然是基於引用計數策略的。換句話說,只要在IE 中涉及COM 對象,就會有循環引用的問題。

例如:

var element = document.getElementById("some_element"); 
var myObject = new Object(); 
myObject.element = element; 
element.someObject = myObject;
登入後複製

DOM 元素(element)與一個原生JavaScript 物件(myObject)之間建立了循環參考。其中,變數myObject 有一個名為element 的屬性指向element 物件;而變數element 也有一個屬性名叫someObject 回指myObject。由於存在這個循環引用,即使將例子中的DOM 從頁面中移除,它也永遠不會被回收。

解決方法:將變數設為null從而切斷變數與它先前引用的值之間的連接。

myObject.element = null; 
 
element.someObject = null;
登入後複製

看完上面的內容,我來談正題。

閉包不會造成記憶體洩漏

由於IE9 之前的版本對JScript 物件和COM 物件使用不同的垃圾收集。因此閉包在IE 的這些版本中會導致一些特殊的問題。具體來說,如果閉包的作用域鏈中保存著一個HTML 元素,那麼就意味著該元素將無法被銷毀請看例子:

function assignHandler(){ 
    var element = document.getElementById("someElement"); 
    element.onclick = function(){ 
        alert(element.id); 
    }; 
}
登入後複製

以上代碼創建了一個作為element 元素事件處理程序的閉包,而這個閉包則又創建了一個循環引用。由於匿名函式保存了一個對assignHandler()的活動物件的引用,因此就會導致無法減少element 的參考數。只要匿名函數存在,element 的引用數至少也是1,因此它所佔用的內存就永遠不會被回收

解決辦法前言已經提到過,把element.id 的一個副本保存在一個變量中,從而消除閉包中該變數的循環引用同時將element變數設為null。

function assignHandler(){ 
    var element = document.getElementById("someElement"); 
    var id = element.id; 
    element.onclick = function(){ 
        alert(id); 
    }; 
    element = null; 
}
登入後複製

總結:閉包並不會造成記憶體洩漏,只是由於IE9之前的版本對JScript物件和COM物件使用不同的垃圾收集,從而導致記憶體無法進行回收,這是IE的問題,所以閉包和內存洩漏沒半毛錢關係。

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

前端熱敏紙小票打印遇到亂碼問題怎麼辦? 前端熱敏紙小票打印遇到亂碼問題怎麼辦? Apr 04, 2025 pm 02:42 PM

前端熱敏紙小票打印的常見問題與解決方案在前端開發中,小票打印是一個常見的需求。然而,很多開發者在實...

神秘的JavaScript:它的作用以及為什麼重要 神秘的JavaScript:它的作用以及為什麼重要 Apr 09, 2025 am 12:07 AM

JavaScript是現代Web開發的基石,它的主要功能包括事件驅動編程、動態內容生成和異步編程。 1)事件驅動編程允許網頁根據用戶操作動態變化。 2)動態內容生成使得頁面內容可以根據條件調整。 3)異步編程確保用戶界面不被阻塞。 JavaScript廣泛應用於網頁交互、單頁面應用和服務器端開發,極大地提升了用戶體驗和跨平台開發的靈活性。

誰得到更多的Python或JavaScript? 誰得到更多的Python或JavaScript? Apr 04, 2025 am 12:09 AM

Python和JavaScript開發者的薪資沒有絕對的高低,具體取決於技能和行業需求。 1.Python在數據科學和機器學習領域可能薪資更高。 2.JavaScript在前端和全棧開發中需求大,薪資也可觀。 3.影響因素包括經驗、地理位置、公司規模和特定技能。

JavaScript難以學習嗎? JavaScript難以學習嗎? Apr 03, 2025 am 12:20 AM

學習JavaScript不難,但有挑戰。 1)理解基礎概念如變量、數據類型、函數等。 2)掌握異步編程,通過事件循環實現。 3)使用DOM操作和Promise處理異步請求。 4)避免常見錯誤,使用調試技巧。 5)優化性能,遵循最佳實踐。

如何實現視差滾動和元素動畫效果,像資生堂官網那樣?
或者:
怎樣才能像資生堂官網一樣,實現頁面滾動伴隨的動畫效果? 如何實現視差滾動和元素動畫效果,像資生堂官網那樣? 或者: 怎樣才能像資生堂官網一樣,實現頁面滾動伴隨的動畫效果? Apr 04, 2025 pm 05:36 PM

實現視差滾動和元素動畫效果的探討本文將探討如何實現類似資生堂官網(https://www.shiseido.co.jp/sb/wonderland/)中�...

如何使用JavaScript將具有相同ID的數組元素合併到一個對像中? 如何使用JavaScript將具有相同ID的數組元素合併到一個對像中? Apr 04, 2025 pm 05:09 PM

如何在JavaScript中將具有相同ID的數組元素合併到一個對像中?在處理數據時,我們常常會遇到需要將具有相同ID�...

JavaScript的演變:當前的趨勢和未來前景 JavaScript的演變:當前的趨勢和未來前景 Apr 10, 2025 am 09:33 AM

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。

console.log輸出結果差異:兩次調用為何不同? console.log輸出結果差異:兩次調用為何不同? Apr 04, 2025 pm 05:12 PM

深入探討console.log輸出差異的根源本文將分析一段代碼中console.log函數輸出結果的差異,並解釋其背後的原因。 �...

See all articles