【问题标题】:Angular directive memory leaks?Angular 指令内存泄漏?
【发布时间】:2015-02-12 13:19:39
【问题描述】:

我正在使用这个简单的 html 文件来重现我发现的内存泄漏:

<!doctype html>
<html>
    <head>
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.6/angular.min.js"></script>
        <script>
            var app = angular.module('testApp', []);

            app.directive('directive1', function() {
                return {
                    template: '<div directive2></div>',
                    scope: true
                };
            });

            app.directive('directive2', function () {
                function LeakObject() {}

                function Foo() {
                    this.bar = function($scope) {
                            $scope.nottheredude;
                    };
                }

                return {
                    scope: true,
                    link: function($scope) {
                            $scope.memoryThatLeaks = new LeakObject();

                            new Foo().bar({});
                            new Foo().bar($scope);
                    }
                };
            });
        </script>
    </head>
    <body ng-app="testApp">
        <button ng-click="show = !show">Toggle</button>
        <div ng-if="show">The directive <div directive1></div></div>
        <div ng-if="!show">Nothing</div>
    </body>
</html>

我有一个指令,它只创建一个新的作用域,并且在它的模板中有另一个指令。

另一个指令做了一些奇怪的事情(我试图将问题缩小到导致泄漏的原因,这是我发现的重现问题的最短代码)。

在我的主 html 中,我只是使用简单的 ng-if 在无和 directive1 之间切换。

注意directive2 还在$scope 上创建了一个名为LeakObject 的新对象。我希望这个对象在我切换回空 div 时被垃圾收集,因为指令的范围应该消失,并且它上面的所有数据都随之消失,但是根据 Chrome 在隐身模式下的堆快照工具,它没有得到未分配。

我试图理解为什么会发生这种情况,以及为什么如果我注释掉 bar 方法中的语句,它不会发生。

重现步骤:

  1. 以隐身方式打开this file
  2. 打开开发工具并转到配置文件
  3. 刷新页面
  4. 点击Toggle 两次(现在您会再次在屏幕上看到Nothing)
  5. 拍摄堆快照
  6. 在过滤器中写入“泄漏”,这样您就可以看到 LeakObject 在不应该存在时仍然存在。

它应该是这样的:

有人可以帮忙/解释一下吗?

【问题讨论】:

  • 显然,这在 Windows 8、Chrome 42 中不是问题
  • 无法在 Ubuntu15/Chome 上重现问题

标签: javascript angularjs memory-leaks


【解决方案1】:

一切都按预期进行, 按照您的步骤操作后,我在快照中看不到任何泄漏对象。

您可以将以下代码添加到链接函数中,以查看指令实际上正在销毁

控制器和指令在它们被销毁之前发出一个事件。在这里,您有机会拆除您的插件和侦听器,并且几乎可以执行垃圾收集。 订阅 $scope.$on('$destroy', ...) 事件

$scope.$on('$destroy',function(){
  //$scope.memoryThatLeaks = null;
  alert('!');
 });

【讨论】:

  • 所以你说你不能重现这个问题,也许是操作系统/浏览器的问题。我,在 OSX Yosemite 上的 Chrome 39.0.2171.71 上运行,它也发生在与我交谈过的其他开发人员身上。我知道指令正在被破坏,这就是为什么它看起来像内存泄漏。
  • 传递给$on('$destroy' 的函数被执行的事实并不能真正证明指令被“破坏”,也不能证明没有内存泄漏。并不是说有内存泄漏,我自己没有调查过。
  • 你是对的,'$destroy' 事件被触发的事实证明 Angular 的流程按预期工作,应该删除指令及其作用域。
  • 我认为这行 new Foo().bar({});新的 Foo().bar($scope);在全局上创建对象,这可能是泄漏的原因。
  • @Moran ""触发 '$destroy' 事件的事实证明 Angular 的流程按预期工作,应该删除指令及其范围" - 如果有是泄漏,即使'$destroy' 被触发,GC 也无法收集指令及其作用域,这就是泄漏。
猜你喜欢
  • 2014-07-18
  • 2016-04-03
  • 2021-09-10
  • 1970-01-01
  • 2013-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多