1. 程式人生 > >談談Js記憶體洩漏的那點事兒

談談Js記憶體洩漏的那點事兒

JavaScript 是一種垃圾收集式語言,這就是說,記憶體是根據物件的建立分配給該物件的,並會在沒有對該物件的引用時由瀏覽器收回。JavaScript 的垃圾收集機制本身並沒有問題,但瀏覽器在為 DOM 物件分配和恢復記憶體的方式上卻有些出入。

Internet Explorer 和 Mozilla Firefox 均使用引用計數來為 DOM 物件處理記憶體。在引用計數系統,每個所引用的物件都會保留一個計數,以獲悉有多少物件正在引用它。如果計數為零,該物件就會被銷燬,其佔用的記憶體也會返回給堆。雖然這種解決方案總的來說還算有效,但在迴圈引用方面卻存在一些盲點。

當兩個物件互相引用時,就構成了迴圈引用,其中每個物件的引用計數值都被賦 1。在純垃圾收集系統中,迴圈引用問題不大:若涉及到的兩個物件中的一個物件

被任何其他物件引用,那麼這兩個物件都將被垃圾收集。而在引用計數系統,這兩個物件都不能被銷燬,原因是引用計數永遠不能為零。在同時使用了垃圾收集和引用計數的混合系統中,將會發生洩漏,因為系統不能正確識別迴圈引用。在這種情況下,DOM 物件和 JavaScript 物件均不能被銷燬。

-----------------------------------------------------------------華麗麗的分割線---------------------------------------------------------

以下是記憶體洩漏的幾種例項:

1、給DOM物件新增的屬性是一個物件的引用。範例: 

var testObject = {}; 
document.getElementById('idname').property = testObject;  //如果DOM不被消除,則testObject會一直存在,造成記憶體洩漏
解決方法:

在window.onunload事件中寫上:

document.getElementById('idname').property = null;         //釋放記憶體

2、DOM物件與JS物件相互引用。範例:

function testObject(element) { 
this.elementReference = element;                      // 為testObject(js)物件的屬性繫結element(DOM)物件
element.property = this;                              // 為element(DOM)物件的屬性繫結testObject(js)物件
} 
new testObject(document.getElementById('idname'));

解決方法:onunload事件中寫上

document.getElementById('idname').property = null;

3、給DOM物件用attachEvent繫結事件。範例:

function doClick() {} 
element.attachEvent("onclick", doClick); 

解決方法:onunload事件中寫上:

 element.detachEvent('onclick', doClick);

4、從外到內執行appendChild。這時即使呼叫removeChild也無法釋放。範例:

var parentDiv = document.createElement("div"); 
var childDiv = document.createElement("div"); 
document.body.appendChild(parentDiv); 
parentDiv.appendChild(childDiv); 

解決方法:從內到外執行appendChild: 

var parentDiv = document.createElement("div"); 
var childDiv = document.createElement("div"); 
parentDiv.appendChild(childDiv); 
document.body.appendChild(parentDiv); 

5、反覆重寫同一個屬性會造成記憶體大量佔用(但關閉IE後記憶體會被釋放)。範例:

for(i = 0; i < 5000; i++) { hostElement.text = "asdfasdfasdf"; 

這種方式相當於定義了5000個屬性!