Memory leak in Ionic(or angular)?

I'm new to both Ionic and Angular, so I'm not sure where the problem would actually lie between the two(if either). I seem to have a problem with ng-repeat not clearing memory. I've written a bare bones example to demonstrate

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");
    }
})

every time you click the picture, the array ng-repeat is using will have an element removed and added 1000 times. But there is something sticking around in memory, causing my actual app to crash.

ionic/angularjs memory leak

Can anyone shed some insight as to if I'm doing something wrong, or if it's actually a bug? I've looked through github and haven't seen a bug report which matches what I'm seeing, and once I've determined it's not just me doing something wrong I'll go make a report.

If you follow the chart, you can see that the issue is the number of Event Listeners that are issued. Due to the way that $watch works within angular, removing an element from an array and then adding a new element doesn't remove the $watch on the old element, causing the number of Event listeners to continue to spawn infinitely.

By default, the $watch() function only checks object reference equality. This means that within each $digest, angular will check to see if the new and old values are the same "physical" object. This means that the vanilla $watch() statement will only invoke its handler if you actually change the underlying object reference.

There are two ways to solve this issue. Firstly, you can use the new Bind Once syntax that is provided in Angular 1.3. Changing your ng-repeat to ng-repeat="card in ::cards" will create a bind only until the expression is evaluated, then destroy the listener. This is ideal for situations where you know that the element will never change once it's been evaluated.

The other method is to use a more aggressive tracking on the elements. ng-repeat="card in cards track by $id" will cause the elements to be tracked by the $id field, and angular will be able to smartly remove the listener when the object with the unique $id no longer exists in the DOM.

Watching both of these in the timeline, you will see that the first option Bind Once will spend more time with no listeners, as it will destroy the listeners after evaluation and only spawn new listeners to add the new elements to the DOM. The second option will spend most of it's time at the upper bounds of listeners for your number of active elements, but will drop all the listeners as elements are removed and add new listeners to replace them.

In the end, Bind Once will be more efficient if you know the elements aren't going to change, only be replaced; Tracking will be more flexible if your elements could change between being added and removed.