天天看點

JavaScript學習筆記(三十八)——記憶體洩露與垃圾回收機制

什麼是記憶體洩露?

程式運作的時候需要用到記憶體,對于持續運作的服務程序,必須要及時釋放記憶體,否則,記憶體占用越來越高,将影響系統性能,甚至導緻程序崩潰。

JavaScript學習筆記(三十八)——記憶體洩露與垃圾回收機制

此時,有些程式已經結束程序,不再用到記憶體,但是沒有及時釋放記憶體,這就叫做記憶體洩露(memory leak)。

為解決記憶體洩露問題,大多數語言提供了自動記憶體管理,減輕程式員手動釋放記憶體的負擔,這被稱為垃圾回收機制(garbage collector)。

JavaScript垃圾回收機制原理:

解決記憶體洩露,垃圾回收機制會定期(周期性)找到那些不再用到的記憶體(變量),然後釋放其記憶體。

現在各大浏覽器通常采用的垃圾回收機制有兩種方式:引用計數、标記清除。

引用計數

該方式主要計算每一個資料(值)被引用的次數。 每當一個資料被一個變量或者其它引用一次,就對該資料的累計次數

+1

。每當減少一個引用次數,就

-1

。當引用次數為

時,就會銷毀該資料,也就是把它當作垃圾來回收掉,進而釋放記憶體。

JavaScript學習筆記(三十八)——記憶體洩露與垃圾回收機制

上圖中,左下角的兩個值,沒有任何引用,即引用次數為

,是以可以将其回收,釋放記憶體。

但是,如果一個值不再需要了,但是引用計數卻不為

,垃圾回收機制就無法釋放這塊記憶體,進而導緻記憶體洩露。

上面代碼中,數組

[1, 2, 3]

是一個值,會占用記憶體。變量

arr

是僅有的對這個值的引用,是以引用次數為

1

。盡管後面的代碼沒有

arr

,它還是持續占用記憶體。

如果增加一行代碼,解除

arr

[1, 2, 3]

的引用,則引用次數為

,這塊記憶體就哭被垃圾回收機制回收,釋放記憶體。

上面代碼中,

arr

重置為

null

,就解除了對

[1, 2, 3, 4]

的引用,引用次數變成了

,記憶體就可以釋放出來了。

但是,通過引用計數方式來釋放記憶體,有一個缺點,就是無法解決循環引用問題。

标記清除

js中最常用的垃圾回收方式就是标記清除。當變量進入環境時,例如,在一個函數中聲明一個變量,就将這個變量标記為"

進入環境

",從邏輯上講,永遠不能釋放進入環境變量所占用的記憶體,因為隻要執行流進入相應的環境,就可能會用到它們。而當變量離開環境時,則将其标記為"

離開環境

"。

function test(){
    var a = 10;    //被标記"進入環境"
    var b = "hello";    //被标記"進入環境"
}
test();    //執行完畢後之後,a和b又被标記"離開環境",被回收
           

垃圾回收機制在運作的時候會給存儲在記憶體中的所有變量都加上标記(可以是任何标記方式),然後,它會去掉處在環境中的變量及被環境中的變量引用的變量标記(閉包)。

而在此之後剩下的帶有标記的變量被視為準備删除的變量,原因是環境中的變量已經無法通路到這些變量了。

最後垃圾回收機制到下一個周期運作時,将釋放這些變量的記憶體,回收它們所占用的空間。

到目前為止,IE、Firefox、Opera、Chrome、Safari的js實作使用的都是标記清除的垃圾回收政策或類似的政策,隻不過垃圾收集的時間間隔互不相同。

是以,并不是說有了垃圾回收機制,程式員就輕松了。你還是需要關注記憶體占用:那些很占空間的值,一旦不再用到,你必須檢查是否還存在對它們的引用。如果是的話,就必須手動解除引用。

參考:

http://www.ruanyifeng.com/blog/2017/04/memory-leak.html

https://blog.csdn.net/oliver_web/article/details/53957021

繼續閱讀