observableArray 和 foreach 绑定的内存泄漏

Posted

技术标签:

【中文标题】observableArray 和 foreach 绑定的内存泄漏【英文标题】:Memory leak with observableArray and foreach binding 【发布时间】: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,但这些工具似乎无法胜任这项工作。有什么建议吗? 这里有一些想法***.com/a/4949098/1842618 【参考方案1】:

我在弄乱你的小提琴并注意到如果你推送具有可观察属性的香草对象而不是推送包装在可观察对象中的香草对象,问题就会消失:

    joes.forEach(function(joe)
            var joeObs = 
                name:ko.observable(joe.Name),
                age:ko.observable(joe.Age);
            self.array.push(joeObs);
        );

对此我没有任何解释。所以我的回答更像是一个问题......真的有什么区别?为什么一个漏一个不漏?

【讨论】:

【参考方案2】:

我们从 jsfiddle 中取出测试用例,单独运行它并进行宾果游戏 - 没有内存泄漏。唷。

似乎它比预期更多地参与了舞蹈!

【讨论】:

以上是关于observableArray 和 foreach 绑定的内存泄漏的主要内容,如果未能解决你的问题,请参考以下文章

如何处理绑定:更改 observableArray 中的数据后的 foreach

在 knout.js 中遍历 observablearray 时,如何检索 foreach 的 ko.computed 运行总和

如何订阅 observableArray 项目的更改

KNOCKOUT JS observableArray重复

无法绑定淘汰的$ parent

淘汰foreach绑定,更新值