【问题标题】:Memory leak in Ionic(or angular)?Ionic(或角度)中的内存泄漏?
【发布时间】:2015-03-15 18:43:56
【问题描述】:

我是 Ionic 和 Angular 的新手,所以我不确定问题在两者之间的实际位置(如果有的话)。我似乎对 ng-repeat 不清除内存有问题。我写了一个简单的例子来演示

http://codepen.io/pen/pvQyxj

index.html

<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
    <title></title>

    <link href="//code.ionicframework.com/nightly/css/ionic.css" rel="stylesheet">

    <!-- ionic/angularjs js -->
    <script src="//code.ionicframework.com/nightly/js/ionic.bundle.js"></script>
    <script src="cordova.js"></script>
    <script src="js/app.js"></script>

  </head>
  <body ng-app="starter">

    <ion-pane>
      <ion-header-bar class="bar-stable">
        <h1 class="title">Ionic Blank Starter</h1>
      </ion-header-bar>
      <ion-content ng-controller="CardsCtrl">
    <div ng-repeat="card in cards" on-tap="start(1000)">
        <img ng-src="{{card.image}}">
    </div>
      </ion-content>
    </ion-pane>
  </body>
</html>

js/app.js

angular.module('starter', ['ionic'])

.run(function($ionicPlatform) {
  $ionicPlatform.ready(function() {
    // Hide the accessory bar by default (remove this to show the accessory bar above the keyboard
    // for form inputs)
    if(window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
    }
    if(window.StatusBar) {
      StatusBar.styleDefault();
    }
  });

}).controller('CardsCtrl', function($scope) {
    $scope.cards = [];


    var addCards = function(_num, y) {
        for (var x = 0; x < _num; x++) 
        {
            $scope.cards.push({
                image:"http://i.imgur.com/QR8mZAt.jpg?"+y
            }); 
        }
    }
    addCards(1, "new");

    var cardDestroyed = function(y) {

        //console.log("destroy");
        $scope.cards.splice(0, 1);
        addCards(1, y);
    };

    $scope.start = function(y){
        console.log("start");
        for (var x = 0; x < y; x++)
        {
            cardDestroyed(y);
        }
        console.log("stop");
    }
})

每次单击图片时,ng-repeat 正在使用的数组都会删除一个元素并添加 1000 次。但是内存中存在一些问题,导致我的实际应用程序崩溃。

任何人都可以了解我是否做错了什么,或者它是否真的是一个错误?我浏览了 github 并没有看到与我所看到的相匹配的错误报告,一旦我确定这不仅仅是我做错了什么,我就会去报告。

【问题讨论】:

    标签: javascript angularjs memory-leaks ionic-framework ng-repeat


    【解决方案1】:

    如果您按照图表,您可以看到问题在于发出的事件侦听器的数量。由于 $watch 在 angular 中的工作方式,从数组中删除一个元素然后添加一个新元素不会删除旧元素上的 $watch,从而导致事件侦听器的数量继续无限生成。

    默认情况下,$watch() 函数仅检查对象引用相等性。这意味着在每个$digest 中,angular 都会检查新值和旧值是否是相同的“物理”对象。这意味着 vanilla $watch() 语句只有在您实际更改底层对象引用时才会调用其处理程序。

    有两种方法可以解决此问题。首先,您可以使用 Angular 1.3 中提供的新的 Bind Once 语法。将您的 ng-repeat 更改为 ng-repeat="card in ::cards" 将仅在计算表达式之前创建绑定,然后销毁侦听器。这对于您知道元素一旦被评估就永远不会改变的情况非常理想。

    另一种方法是对元素使用更积极的跟踪。 ng-repeat="card in cards track by $id" 将导致元素被 $id 字段跟踪,当具有唯一 $id 的对象不再存在于 DOM 中时,angular 将能够智能地移除侦听器。

    在时间轴中观察这两个选项,您会看到第一个选项 Bind Once 将在没有监听器的情况下花费更多时间,因为它会在评估后销毁监听器并仅生成新的监听器以将新元素添加到 DOM。第二个选项将大部分时间花在您活动元素数量的侦听器上限上,但会在删除元素时删除所有侦听器并添加新侦听器来替换它们。

    最后,如果你知道元素不会改变,只会被替换,Bind Once 会更有效率;如果您的元素可以在添加和删除之间发生变化,则跟踪将更加灵活。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-10-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-27
      • 1970-01-01
      • 1970-01-01
      • 2015-02-10
      • 1970-01-01
      相关资源
      最近更新 更多