JavaScript記憶體洩露

韓子遲發表於2015-07-09

譯者前言

最近簡單瞭解了下JavaScript的閉包和垃圾回收機制(GC),這中間也不得不接觸記憶體洩露這個概念。然後不小心找到了這篇文章,看下來後理解了不少東西,於是譯之與大家分享。

在JavaScript中,我們很少考慮到記憶體管理,但是它又是真實存在的。當我們建立一個變數,接著使用它們,然後瀏覽器的垃圾回收機制對它們進行回收。

雖然我們很少考慮記憶體管理,但是當應用程式越來越複雜並且ajax化之後,我們開啟一個網頁,過段時間發現瀏覽器消耗的記憶體不斷增大,很有可能是因為記憶體洩露,這時我們不得不考慮記憶體管理。

JavaScript的記憶體管理

JavaScript記憶體管理的核心也就是JavaScript垃圾回收機制,而存在在記憶體中的資料包括堆疊中的資料(區域性變數,正在被呼叫的方法的引數)以及全域性變數;而物件如果被引用或者存在在一個引用鏈中時,也會存在在記憶體中。關於這點可以參考JavaScript垃圾回收機制。

下面再舉個GC的例子:

記憶體結構如下:

在step(1)後,body.innerHTML被清空了,所以它的子節點都被移除了。但是元素#id是個例外,它依然能通過menu.elem訪問,所以它依然存在在記憶體中,當然如果你無法訪問它的父節點,因為它被移除了。

單個的dom元素可能存在在記憶體中哪怕它的父節點已經被移除。

在step(2)後,window.menu被重新賦值引用,所以原來的menu不可訪問了,於是自動被GC回收。

而閉包經常會引起迴圈引用:

dom元素elem通過onclick引用了一個function,而這個function內部也能引用外部作用域裡的dom變數elem。

甚至onclick函式裡沒有程式碼,該迴圈引用同樣成立。而一些像addEventListener/attachEvent的方法也會形成類似的迴圈引用。

記憶體洩露

當一個物件不再被引用,但是瀏覽器由於某些原因並沒有釋放記憶體,這時就會引起記憶體洩露。瀏覽器問題,瀏覽器的外掛問題,或者我們自己的程式碼問題都可能引起記憶體洩露。

在前面垃圾回收機制一文中我們瞭解,在IE8以下時,dom物件的迴圈引用就會引起記憶體洩露(更進一步講,其實是COM物件)

dom物件外,任何的COM物件包括XMLHttpRequest都會引起記憶體洩露。

IE的記憶體洩露的解決方式是打破迴圈引用。

我們把dom元素elem賦值為null,所以onclick裡的function不會再引用elem,所以這個迴圈被打破了。

關於XmlHttpRequest的記憶體管理和洩露:

以下的程式碼在IE9以下完美洩露…

讓我們來看看記憶體樹:

 

  • JQuery中針對記憶體洩露的措施以及新的洩露

jQuery這塊還沒仔細研究過,略…

在chrome開發者工具欄中,有個timeline,能或多或少檢測記憶體洩露。

打賞支援我翻譯更多好文章,謝謝!

打賞譯者

打賞支援我翻譯更多好文章,謝謝!

JavaScript記憶體洩露

相關文章