一文看懂前端垃圾回收

簡介

javascript裏面變量再也不使用,就是垃圾,咱們就應該把它清除掉,以避免佔用內存。
可是垃圾回收過程是一個近似且不完美的方案,由於某塊內存是否還有用,屬於「不可斷定的」問題,意味着靠算法是解決不了的。
目前主流瀏覽器使用的是標記清除,在介紹標記清除前先介紹下爲何引用計數會被淘汰。javascript

引用計數

引用計數最先由 Netscape Navigator 3.0 採用,但很快就遇到了嚴重的問題:循環引用。
所謂循環引用,就是對象 A 有一個指針指向對象 B,而對象 B 也引用了對象 A。html

function problem() {
let objectA = new Object(); 
let objectB = new Object();
objectA.someOtherObject = objectB; 
objectB.anotherObject = objectA;
}

在這個例子中,objectA 和 objectB 經過各自的屬性相互引用,意味着它們的引用數都是 2。在 標記清理策略下,這不是問題,由於在函數結束後,這兩個對象都不在做用域中。而在引用計數策略下objectA 和 objectB 在函數結束後還會存在,由於它們的引用數永遠不會變成 0。若是函數被屢次調 用,則會致使大量內存永遠不會被釋放。爲此,Netscape 在 4.0 版放棄了引用計數,轉而採用標記清理。前端

標記清除

  • 1.垃圾回收程序運行的時候,會標記內存中存儲的全部變量。
  • 2.而後它會將全部在上下文中的變量,以及被在上下文中的變量引用的變量的標記去掉。
  • 3.在此以後再被加上標記的變量就是待刪除的了,緣由是任何在上下文中的變量都訪問不到它們了。

可達性

這裏介紹下第二步驟的一個實現。
可達性就行可訪問性,window(globle)能訪問某個變量A(無論經過幾層取值),那A就是可達的,那麼A就有可能再將來會被用,A就不會被刪除。
咱們看一下下圖就能明白,左邊可達,右邊不可達,右邊會再某個階段會v8引擎回收
java

相關概念

閉包

明白了垃圾回收的概念,理解閉包就簡單多了。
閉包爲啥不銷燬,由於當前函數執行完的返回值(通常是個函數)被外層上下文中的某個變量引用了,因此閉包中的環境可達,因此不會被銷燬。
可是也由於不會被銷燬,因此咱們應該注意一下內存泄漏,也就是若是閉包占用的內存特別多,又把它賦給全局變量。並且這個操做咱們是不斷的進行的,那個內存就會越佔越多,也就是發生了內存泄漏。es6

weakmap

還有個相關的考點,就是weakmap爲何不會被gc(Garbage Collection,垃圾收集)
由於它對於值的引用都是不計入垃圾回收機制的,因此名字裏面纔會有一個"Weak",表示這是弱引用。
防止內存泄漏咱們須要手動置null。
map的鍵是對象,這個引用當於永遠可達,這樣很差,會有內存泄漏。
爲了不咱們忘記置Null,es6添加了weakmap這種數據結構,只要所引用的對象的其餘引用都被清除,垃圾回收機制就會釋放該對象所佔用的內存。也就是說,一旦再也不須要,WeakMap 裏面的鍵名對象和所對應的鍵值對會自動消失,不用手動刪除引用面試

性能優化

  • 經過 const 和 let 聲明提高性能
    由於 const和 let 都以塊(而非函數)爲做用域,因此相比於使用 var,使用這兩個新關鍵字可能會更早地讓垃圾回收程序介入,儘早回收應該回收的內存。
  • 多解除引用(閉包)
    優化內存佔用的最佳手段就是保證在執行代碼時只保存必要的數據。若是數據再也不必要,那麼把它設置爲 null,從而釋放其引用。這也能夠叫 做解除引用。這個建議最適合全局變量和全局對象的屬性。局部變量在超出做用域後會被自動解除引用,算法

    參考資料

    1.垃圾回收
    2.JavaScript 內存泄漏教程
    3.前端面試:談談 JS 垃圾回收機制
    4.MDN-內存管理
    5.javascript高級程序設計第4版本segmentfault

相關文章
相關標籤/搜索