【发布时间】:2014-01-09 11:52:14
【问题描述】:
我们有一个 SPA,它通过 AJAX 获取小批量的项目,并使用它们来填充通过 foreach 绑定到 DOM 的淘汰赛 observableArray。
当新数据到达时,我们使用 removeAll() 清除旧数组并将新项目推入。使用 Chrome 分析工具,我们发现这会导致内存泄漏,大量数组和闭包悬空。获取的次数越多,泄漏就越大。
我们已经构建了一个简单的测试用例来演示这个问题(参见fiddle)。重现:
- 使用 Chrome,打开开发工具面板并选择“配置文件”>“记录堆分配”
- 单击一次以获取一些数据
- 启动分析器并拍摄堆快照
- 点击很多次
- 拍摄另一个快照并与第一个进行比较
HTML:
<div data-bind="click:go,
text:(clickCount()==0)
? 'click once then take a heap snapshot'
: 'click me lots then take another heap snapshot to compare'"
style="cursor:pointer"></div>
<ul data-bind="foreach:array">
<div data-bind="text:$data.name"></div>
<div data-bind="text:$data.age"></div>
</ul>
Javascript:
var getJoes = function(){
var joes=[];
for(var i=0;i<10;i++)
{
var name="Joe";
var age=((Math.random()*10)+1)>>0;
joes.push({Name:name,Age:age});
}
return joes;
};
function viewModel(){
var self=this;
self.array = ko.observableArray();
self.clickCount=ko.observable(0);
self.go = function(){
self.clickCount(self.clickCount()+1);
self.array.removeAll();
var joes=getJoes();
joes.forEach(function(joe){
var joeObs = ko.observable({
name:ko.observable(joe.Name),
age:ko.observable(joe.Age)});
self.array.push(joeObs);
});
};
}
ko.applyBindings(new viewModel());
这是一个错误还是我们遗漏了什么?
【问题讨论】:
-
可能存在对未发布的旧 DOM 元素的引用。
-
他们不会出现在堆快照中吗?唯一未收集的东西似乎是:(闭包)、(数组)、数组、系统/上下文、对象、ko.bindingContext 和 Pos
-
是的,你可能是对的。您是否尝试过分析任何其他浏览器?
-
我们查看了 Firefox,但这些工具似乎无法胜任这项工作。有什么建议吗?
标签: javascript knockout.js memory-leaks ko.observablearray