Javascript 敲除ViewModel计算的垃圾回收
我一直在努力跟踪我的应用程序代码中的垃圾收集问题。我已经将其剥离为纯敲除代码,根据计算属性的创建方式收集创建的对象似乎存在问题 请参阅以下JS fiddle:Javascript 敲除ViewModel计算的垃圾回收,javascript,knockout.js,garbage-collection,Javascript,Knockout.js,Garbage Collection,我一直在努力跟踪我的应用程序代码中的垃圾收集问题。我已经将其剥离为纯敲除代码,根据计算属性的创建方式收集创建的对象似乎存在问题 请参阅以下JS fiddle: 打开Chrome分析器 拍摄堆快照 单击全部生成 拍摄另一个堆快照 比较快照 正确收集Test1时,Test2和Test3仍保留在内存中 请参阅viewmodel的以下代码: function ViewModel() { this.test1 = null; this.test2 = null; this.test
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“三”计算不使用this或self来引用“一”和“二”可观察属性。有人能解释一下这里发生了什么吗?我想在闭包包含对象引用的方式中有些东西,但我不明白为什么
希望我没有错过任何东西。如果有,请告诉我,非常感谢您的回复。我认为问题在于您在代码中使用&&时,它将返回一个布尔值,正确地说是“true” 那么这个.three==真的而不是self.one+self.two,如果这是意图? 当你处理
this.three.dispose();
你只要去掉一个布尔值
“函数Test2()”中有一个额外的“this”是有原因的吗?我认为这是一个经典的循环引用问题 让我们打电话:
var test2 = new Test2();
var test1 = new Test1();
现在test2.3包含了test2的引用!因为您确实要求knockout将函数(){…}与“this”对象test2对象绑定
由于test2自然地持有test2.3的引用,因此现在在两个对象之间获得了一个循环引用
您可以看到这与Test3相同
但是对于Test1,我们调用:
var test2 = new Test2();
var test1 = new Test1();
test1.three包含两个对象的引用(test1.one和test2.two),test1包含三个引用(test1.one、test1.two和test1.three),没有循环引用
在Java和Objective-C等其他一些语言中,该语言支持弱引用来处理此类问题。但到目前为止,弱引用还没有在Javascript中实现
+谢谢你的提问!它让我的大脑有些旋转,帮助我更了解Javascript:)与所有现代浏览器一样,Chrome使用标记和清除算法进行垃圾收集。发件人: 该算法假设一组称为根的对象(在JavaScript中,根是全局对象)的知识。垃圾收集器将定期从这些根开始,查找从这些根引用的所有对象,然后查找从这些根引用的所有对象,等等。因此,从根开始,垃圾收集器将查找所有可访问的对象并收集所有不可访问的对象 垃圾收集器不会立即运行,这就是为什么即使已取消引用对象,您仍然可以在Chrome的快照中看到它们(编辑:如前所述,运行堆快照首先运行垃圾收集器。可能它没有处理所有内容,因此没有清除对象;请参见下文) 通常触发垃圾收集器的一件事是创建新对象。我们可以用你的例子来验证这一点。完成问题中的步骤后,单击“Make1”并拍摄另一个堆快照。您应该看到Test2已经消失了。现在再做一次,您将看到Test3也消失了 还有一些注意事项:
dispose
调用,所有对象都将被清除我应该澄清一下。我相信,即使Test2和Test3实例仍然引用引用返回实例的计算实例,它们也会从ViewModel“main program”中分离出来,作为一个组进行垃圾收集。这有意义吗?我发布了()这促使Michael最好回答这个问题。我认为它可能值得分享,因为它可能会提供更多的见解和背景。您可能想知道为什么test3.3使用的是“self”,而不是“self.one”和“self.two”。这是因为在js中,self.one()实际上就是self['one']()。谢谢你的回答。我相信您所说的是正确的,但我不确定这是否回答了为什么对象Test2和Test3不是GC'd。我已经使用
delete this.test2
和delete this删除了对viewmodel中创建的实例的引用。test3
是否应该是实例对象对于GC是孤立的,即使它们具有内部引用循环?:)垃圾收集器无法处理循环引用。你可以用谷歌搜索这个主题。删除this.test2仅删除test2 hold by viewModel对象的引用。此答案是错误的。看看我提供的答案。我很高兴看到Michael对js mark和sweep的解释。Javascript的根对象架构师可以很容易地找到树中对象的依赖性。我不知道。谢谢你的回答。This.one和This.two是在任何时候都可以返回布尔值的函数。三是具有dispose function属性的computed。我不认为这是我的问题。请参阅:和状态不可访问的对象被清除,并且在拍摄快照时运行GC。不过,我明天会调查你的答案。另外,我关于谷歌集团的问题只是与此相关。不是同一个问题,但我将根据这个答案进行调查。但现在是凌晨2点45分,我应该睡着了。谢谢谢谢你的链接。我已将其添加到答案中。谢谢Michael,我确认Test2消失