接上篇《JS特性性能缺陷及JIT的解決方案》,這里總結下的Javascript垃圾回收機制。
一. 枚舉Javascript引擎分配內存的場景:
1. Object
new Object(); new MyConstructor(); { a: 4, b: 5 } Object.create();
2. 數組
new Array();
[ 1, 2, 3, 4 ];
3. 字符串
new String(“hello hyddd”);
“<p>” + e.innerHTML + “</p>”
隨帶一說,javascript的字符串和.Net一樣,使用資源池和copy on write方式管理字符串。
4. 函數對象
var x = function () { ... } new Function(code);
5. 閉包
function outer(name) { var x = name; return function inner() { return “Hi, “ + name; } }
閉包和prototype不一樣,以上函數為例,當調用outer時,會生成並返回一個對象(隱含變量x),每次調用都創建一個,而prototype則是每次都返回同一個而對象(即:無論多少次調用,只創建一個對象)。
二. GC方案
相對其他語言的復雜的GC方案,Javascript的GC相對還是比較簡單的。
1. Javascript引擎基礎GC方案是(simple GC):mark and sweep(標記清除),即:
(1)遍歷所有可訪問的對象。
(2)回收已不可訪問的對象。
2. GC的缺陷
和其他語言一樣,javascript的GC策略也無法避免一個問題:GC時,停止響應其他操作,這是為了安全考慮。而Javascript的GC在100ms甚至以上,對一般的應用還好,但對於JS游戲,動畫對連貫性要求比較高的應用,就麻煩了。這就是新引擎需要優化的點:避免GC造成的長時間停止響應。
3. GC優化策略
David大叔主要介紹了2個優化方案,而這也是最主要的2個優化方案了:
(1)分代回收(Generation GC)
這個和Java回收策略思想是一致的。目的是通過區分“臨時”與“持久”對象;多回收“臨時對象”區(young generation),少回收“持久對象”區(tenured generation),減少每次需遍歷的對象,從而減少每次GC的耗時。如圖:
這里需要補充的是:對於tenured generation對象,有額外的開銷:把它從young generation遷移到tenured generation,另外,如果被引用了,那引用的指向也需要修改。
(2)增量GC
這個方案的思想很簡單,就是“每次處理一點,下次再處理一點,如此類推”。如圖:
這種方案,雖然耗時短,但中斷較多,帶來了上下文切換頻繁的問題。
4. 總結
因為每種方案都其適用場景和缺點,因此在實際應用中,會根據實際情況選擇方案。
比如:低 (對象/s) 比率時,中斷執行GC的頻率,simple GC更低些;如果大量對象都是長期“存活”,則分代處理優勢也不大。