【问题标题】:Memory leak with KnockoutJS foreach binding与 KnockoutJS foreach 绑定的内存泄漏
【发布时间】:2017-04-06 07:46:37
【问题描述】:

在 Google Chrome 中运行我的 KnockoutJS v3.4.2(测试)应用程序时遇到了问题。
我的页面的内存使用量不断增加。

测试代码是一段非常简单的代码,每秒都会改变一个可观察数组中的项目:

HTML:

<html>
    <head>
        <title>KnockoutJS</title>
    </head>
    <body>
        <h1>Foreach test</h1>
        <ul id="ul-numbers" data-bind="foreach: { data: listOfItems }">
            <li>
                <span data-bind="text: $data"></span>
            </li>
        </ul>

        <script type="text/javascript" src="./lib/knockout.js"></script>
        <script type="text/javascript" src="./index.js"></script> 
    </body>
</html>

JavaScript:

var vm = {
    listOfItems: ko.observableArray()
};

window.setInterval(function updateList(){
    var array = [];

    for(var i = 0 ; i < 1000; i++){
        var num = Math.floor( Math.random() * 500);
        array.push(num);
    }

    vm.listOfItems(array);
}, 1000);

ko.applyBindings(vm);

内存使用情况:

  • 在 Firefox 中,内存使用量不会增加:
    开始:459.6 MB ---> +- 1 小时后:279.4 MB

  • 在 chrome 中,内存使用量不断增加(单个选项卡的内存):
    开始:52.912 MB ---> +- 1 小时后:566.120 MB

  • 在边缘,内存使用量也在不断增加(单个选项卡的内存):
    开始:109.560 MB ---> +- 1 小时后:385.820 MB

我在这段代码 sn-p 中做错了吗?或者这会是 Google Chrome 或 KnockoutJS 中的错误吗?

【问题讨论】:

  • 如果你不使用array,而是在函数开头调用vm.listOfItems.removeAll(),然后在循环内调用vm.listOfItems.push(num)(省略最后对vm.listOfItems(array)的调用)怎么办?
  • 或者,您可以尝试vm.listOfItems(array.slice(0)); 以防止 Knockout 保留对原始 array 的引用并允许 GC 处理它
  • 使用 removeAll 进行测试,但行为仍然相同。
  • 也经过测试。注意到 JS 内存没有增长,只有 私有内存(我猜是关于 DOM 元素)。所以我认为问题与Chrome有关。
  • 我在 Chrome 中测试过。您可以右键单击 Chrome 的任务管理器并选择许多其他参数进行监控。 JavaScript Memory 参数在测试期间不会增加。但是 Private Memory 可以。

标签: javascript html google-chrome knockout.js microsoft-edge


【解决方案1】:

显然这是一个浏览器问题。

当我现在运行我的测试项目时,内存并没有增加。
测试项目可以在这里找到:https://github.com/knockout/knockout/issues/2223

已在 Google chrome 版本“58.0.3029.110”中解决。

【讨论】:

    【解决方案2】:

    即使您要替换 observable 中的数组,它们仍然附加到 DOM。在向数组添加新元素之前,您需要手动删除它们。

    类似这样的:

    var vm = {
        listOfItems: ko.observableArray()
    };
    
    window.setInterval(function updateList(){
        var array = [];
        vm.listOfItems.removeAll();//<--this is the important line
        for(var i = 0 ; i < 1000; i++){
            var num = Math.floor( Math.random() * 500);
            array.push(num);
        }
    
        vm.listOfItems(array);
    }, 1000);
    
    ko.applyBindings(vm);
    

    请参阅本文中的#2:https://auth0.com/blog/four-types-of-leaks-in-your-javascript-code-and-how-to-get-rid-of-them/

    【讨论】:

    • 这并不能解决问题,我们已经尝试过了。 (请参阅我的问题的 cmets)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-06-29
    • 2019-12-18
    • 2012-05-25
    • 1970-01-01
    • 2022-07-14
    • 2012-10-25
    相关资源
    最近更新 更多