2012-01-17 103 views
10

我剛剛爲一位新開發人員提供了一些面試機會,並且JavaScript是我角色的重要組成部分,爲...招募。說實話,候選人不是很好,但他並沒有真正理解JavaScript,但是在採訪中,他將JavaScript與C#混淆,並開始討論JS中的內存泄漏。我想介入,但是在那之後,我意識到我對JS的內存泄漏知之甚少,除了它們耗盡大量內存並減慢速度之外。JavaScript中的內存泄漏:它們是什麼,如何識別它們以及如何創建它們

在採訪中想到這件事時,我唯一能記住的就是OReilly的Def Guide(認爲這是第四版)提及Mark和Sweeper Garbage Collections。但是,自從我讀到這一點以來,這種情況一直在消退,我無法真正展開。關於這個問題,我發現很少,這個問題很簡單明瞭(除了克羅克福德的一篇文章之外,還不太清楚)。

有人可以儘可能簡單地總結一下:什麼是JS中的內存泄漏,我們如何發現它們,如何創建它們 - 我一直在寫JS多年,這完全打擊了我的知識和信心,我從來沒有真正想過!

回答

4

實際上,「真正的」內存泄漏不應該在有自動垃圾收集語言是可能的。因此,如果存在內存泄漏,它在下層引擎中總是出錯(例如,某些IE中的named function expressions問題)。

因此,在我們澄清之後,仍然有可能通過javascript獲得大量內存並保持不釋放狀態。但這不是真正的內存泄漏。例如,每個function call在ECMAscript中創建一個閉包。除此之外,詞法閉包還可以複製對每個父上下文數據(激活和可變對象)的引用。所以這需要一些記憶,特別是如果你創造了很多關閉。

Javascript DOM世界的另一個例子:我們使用new Image()創建動態圖像,並將源設置爲大圖像。現在,我們有一個對圖像的引用,它不能被垃圾收集,直到所有引用都消失或未被使用(即使一個好的內存工具將正確地告訴你內存被用於圖像而不是用於JavaScript)。

但實際上這些是唯一的情況下,你真的可以用這種語言「泄漏」內存。再一次,它不是真的像C malloc()那樣泄漏內存,你忘記了free()那一節。由於ECMAscript中沒有動態內存管理,這些東西完全超出了你的範圍。

+0

好吧,這是一個內存泄漏。這就像說「忘記打電話免費不是內存泄漏,只是不釋放內存」 – Raynos 2012-01-17 15:30:57

+0

@Raynos:沒有其他不同的故事。 – jAndy 2012-01-17 15:33:43

+0

[他們有什麼不同](https://gist.github.com/1627097) – Raynos 2012-01-17 15:36:48

1

JavaScript通過所有瀏覽器實現不同。但有一個標準,所有的瀏覽器應該遵循:ECMAscript

考慮到所有現代語言都實現了它自己的版本reference counting,所以避免內存泄漏的最佳方法是將所有未使用的變量引用爲null。

3
var trolls = (function() { 
    var reallyBigObject = eatMemory(); 

    // make closure (#1) 
    // store reallyBigObject in closure 
    (function() { 
    var lulz = reallyBigObject; 
    })(); 

    // make another closure (#2) 
    return function() { 
    return 42; 
    }; 
})(); 

你會期望trolls僅僅是function() { return 42; }和你所期望的reallyBigObject被刪除和垃圾收集。

這不是,因爲如果單個閉包(#1)引用外部範圍中的變量。然後所有閉包(#2也)引用該變量。

僅僅因爲你對#2的引用意味着你有一個對reallyBigObject的引用,它在#2死後纔會被清除。

現在考慮一下你的平均封閉重型建築,你將所有東西都封閉在一起,並將它們嵌套10層。您可以看到持有對對象的引用是多麼容易。

請注意上述細節適用於v8。任何完全ES5兼容的瀏覽器將與

var trolls = (function() { 
    var reallyBigObject = eatMemory(); 
    return function() {}; 
})(); 

泄漏因爲每個內部函數必須具有在外部範圍定義的每個閉合變量的引用,按照ES5。大多數瀏覽器都採用快捷方式,並且以不可知的方式對其進行優化。

+0

我不認爲現代GC是愚蠢的。相信我,現在的GC很好地分析這種東西。但無論如何我們應該採訪@gsnedders。 – jAndy 2012-01-17 15:52:47

+1

@jAndy他們是這麼愚蠢,這正是v8的工作原理。任何內部函數都共享同一個閉包上下文對象。該閉包上下文對象包含函數上所有閉包所需的所有變量的聯合。這比ES5規範所說的更好,ES5規範說任何內部函數都必須存儲對閉包中可用的每個變量的引用。 – Raynos 2012-01-17 16:06:58

相關問題