JavaScript採用垃圾自動回收機制,運行時環境會自動清理再也不使用的內存,所以javascript無需像C++等語言同樣手動釋放無用內存。javascript
在這以前先說一下垃圾回收的兩種方式:引用計數與標記清除。
引用計數方式會爲每一個已分配內存單元設置計數器,當計數器減小到0的時候就意味着該單元沒法再被引用,將會被清除。 java
有一個問題是,當存在循環引用時,內存單元的計數器將永遠不爲0,內存的釋放會比較複雜(須要使用到弱引用)。 node
obj.val = obj2; obj2.val = obj;
標記清除方式維護一條鏈表,當變量進入scope時被加入這條鏈表,移出scope時被從鏈表剔除。當gc被激活時,首先爲每一個變量打上一個標記,而後清除存在於那條鏈表的變量的標記以及變量引用的成員的標記。最後,再也不使用到的變量仍舊被gc標記着,將被釋放,包括循環引用。web
若是一段再也不使用的內存未獲得回收,將致使內存泄露, 它將一直佔據着內存而沒法被利用,可能形成系統運行緩慢,瀏覽器崩潰等問題。瀏覽器
關於瀏覽器的javascript實現使用哪一種回收機制,衆說紛紜,感受貴圈好亂。app
我google了一下,http://www.ibm.com/developerworks/web/library/wa-memleak/?S_TACT=105AGX52&S_CMP=cn-a-wa 提到IE以及火狐都使用引用計數的機制回收DOM對象, http://blogs.msdn.com/b/ericlippert/archive/2003/09/17/53038.aspx 說JScript採用 nongenerational mark-and-sweep garbage collector(一種標記清除),還有資料提到現代瀏覽器都使用標記清除回收javascript垃圾。測試
總結爲,瀏覽器回收JavaScript內存採用標記清除,使用引用計數回收宿主對象(如Dom、Bom、ActiveX Object)。優化
根據我在IE上作的測試,javascript對象間的循環引用不會引起內存泄露。google
setInterval(function(){ for(var i = 0; i < 100000; i++){ var obj = {}, obj2 = {}; obj.val = obj2; obj2.val = obj; } }, 10);
內存使用呈週期性變化,一直穩定,看來不用擔憂javascript對象的循環引用問題。spa
既然Dom採用引用計數回收內存,那是否存在內存泄露問題?
var nodeHold = [], interval = setInterval(function(){ for(var i = 0, length = 1000; i < length; i++){ var node = document.createElement("div"), obj = {}; node.val = obj; obj.val = node; document.body.appendChild(node); document.body.removeChild(node); } }, 500);
在IE7與IE8上,內存直線上升。
與 http://blogs.msdn.com/b/ericlippert/archive/2003/09/17/53038.aspx 所稱一致,緣由是javascript的垃圾回收管不了Dom對象,且Dom使用引用計數回收方式,致使循環引用沒法回收。前提是Dom必須先加到文檔樹再刪除(我猜想是爲真正的Dom對象分配內存,而這不屬於javascript)。
要注意的是,IE9+並不存在循環引用致使Dom內存泄露問題,多是微軟作了優化,或者Dom的回收方式已經改變。