[英]Knockout ViewModel computed garbage collection
我一直在嘗試在我的應用程序代碼中跟蹤垃圾回收的任何問題。 我已經將其簡化為純敲除代碼,並且根據計算屬性的創建方式收集創建的對象似乎存在問題。
請參閱以下JS小提琴: http : //jsfiddle.net/SGXJG/
請查看以下視圖模型代碼:
function ViewModel() {
this.test1 = null;
this.test2 = null;
this.test3 = null;
}
ViewModel.prototype = {
makeAll: function () {
this.make1();
this.make2();
this.make3();
},
make1: function () {
this.test1 = new Test1();
this.test1.kill();
delete this.test1;
},
make2: function () {
this.test2 = new Test2();
this.test2.kill();
delete this.test2;
},
make3: function () {
this.test3 = new Test3();
this.test3.kill();
delete this.test3;
},
};
ko.applyBindings(new ViewModel());
這是三個測試類:
function Test1() {
var one = this.one = ko.observable();
var two = this.two = ko.observable();
this.three = ko.computed(function () {
return one() && two();
});
}
Test1.prototype = {
kill: function () {
this.three.dispose();
}
};
function Test2() {
this.one = ko.observable();
this.two = ko.observable();
this.three = ko.computed(function () {
return this.one() && this.two();
}, this);
}
Test2.prototype = {
kill: function () {
this.three.dispose();
}
};
function Test3() {
var self = this;
self.one = ko.observable();
self.two = ko.observable();
self.three = ko.computed(function () {
return self.one() && self.two();
});
self.kill = function () {
self.three.dispose();
};
}
區別在於Test1的“三”計算不使用此函數或self來引用“一個”和“兩個”可觀察的屬性。 有人可以解釋這里發生了什么嗎? 我想閉包包含對象引用的方式有些問題,但我不明白為什么
希望我不會錯過任何東西。 讓我知道是否感謝您的任何答復。
與所有現代瀏覽器一樣,Chrome使用標記清除算法進行垃圾收集。 從MDN :
該算法假定了解一組稱為根的對象(在JavaScript中,根是全局對象)。 垃圾收集器會定期從這些根目錄開始,查找從這些根目錄引用的所有對象,然后從這些根目錄引用所有對象,依此類推。因此,從根目錄開始,垃圾收集器將查找所有可訪問對象並收集所有非對象。可達的對象。
垃圾收集器不運行的時候了,這就是為什么你仍然看到即使你取消引用它們(編輯Chrome的快照的對象:如前所述這里 ,運行堆快照首先運行垃圾收集器可能它不處理一切。因此不會清除對象;請參見下文。)
通常會觸發垃圾收集器的一件事是創建新對象。 我們可以使用您的示例對此進行驗證。 完成問題中的步驟后,單擊“ Make1”並拍攝另一個堆快照。 您應該看到Test2消失了。 現在再做一次,您會發現Test3也消失了。
更多注意事項:
Chrome不會在垃圾回收期間清理所有內容。 “ [Chrome] ...在大多數垃圾回收周期中僅處理部分對象堆。” ( google.com )因此,我們看到需要運行幾次垃圾收集器才能清除所有內容。
只要清除了對某個對象的所有外部引用,該對象最終將由垃圾收集器清除。 在您的示例中,您甚至可以刪除dispose
調用,所有對象都將被清除。
我認為這是一個經典的循環參考問題。
讓我們打電話:
var test2 = new Test2();
現在test2.three擁有test2的引用! 因為您從字面上要求敲除將一個function(){...}與該“此”對象(即test2對象)綁定。
由於test2自然擁有test2.three的引用,因此您現在在兩個對象之間有了一個循環引用!
您可以看到與您的Test3相同。
但對於Test1,我們稱之為:
var test1 = new Test1();
test1.three保存兩個對象的引用(test1.one和test2.two),test1保存三個引用(test1.one,test1.two和test1.three),沒有循環引用。
在其他一些語言(如Java和Objective-C)中,該語言支持弱引用來處理此類問題。 但是到目前為止,弱引用尚未在Javascript中實現。
+1感謝您的提問! 它使我的大腦有些旋轉,幫助我更多地了解了Javascript :)
我認為問題在於您在代碼中使用&&,它將返回一個布爾值,正確為“ true”。
this.three = ko.computed(function () {
// !
return this.one() && this.two();
},
那么this.three == true而不是self.one + self.two如果這是意圖? 當你處置
this.three.dispose();
您只是擺脫了布爾值。
有什么理由在“函數Test2()”中增加一個“ this”?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.