談談Js記憶體洩漏的那點事兒
JavaScript 是一種垃圾收集式語言,這就是說,記憶體是根據物件的建立分配給該物件的,並會在沒有對該物件的引用時由瀏覽器收回。JavaScript 的垃圾收集機制本身並沒有問題,但瀏覽器在為 DOM 物件分配和恢復記憶體的方式上卻有些出入。
Internet Explorer 和 Mozilla Firefox 均使用引用計數來為 DOM 物件處理記憶體。在引用計數系統,每個所引用的物件都會保留一個計數,以獲悉有多少物件正在引用它。如果計數為零,該物件就會被銷燬,其佔用的記憶體也會返回給堆。雖然這種解決方案總的來說還算有效,但在迴圈引用方面卻存在一些盲點。
當兩個物件互相引用時,就構成了迴圈引用,其中每個物件的引用計數值都被賦 1。在純垃圾收集系統中,迴圈引用問題不大:若涉及到的兩個物件中的一個物件
-----------------------------------------------------------------華麗麗的分割線---------------------------------------------------------
以下是記憶體洩漏的幾種例項:
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個屬性!