AngularJS Memory Leak Playground (Simple example)
Playground for detecting potential memory leaks when using AngularJS. Counting controller initializations and displaying memory usage.
HTML
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular-route.js"></script>
<script type="text/ng-template" id="tab.html">
<p>Auto switching:
<button ng-click="startAutoSwitching()">start</button>
<button ng-click="stopAutoSwitching()">stop</button>
</p>
<p>Name: {{name}}</p>
<p>Controller instantiations: {{controllerInstantiations}}</p>
<p>Heap size: {{heapSize}}</p>
</script>
<div class="main">
<ul class="menu">
<li><a href="#/this">This</a></li>
<li><a href="#/that">That</a></li>
</ul>
<ng-view></ng-view>
</div>
CSS
.main {
font-family: Helvetica, Arial, sans-serif;
font-size: 14px;
padding: 10px;
}
.menu {
margin-bottom: 10px;
}
.menu li {
display: inline;
}
p {
margin-bottom: 10px;
}
JavaScript
var app = angular.module('myApp', ['ngRoute']);
app.value('constants', {
'numOfRandomNumbers': 1000000,
'shouldRegister': true,
'shouldUnregister': true,
'autoSwitchTimeout': 1000 });
function heapSize() {
if (!performance.memory) {
return('!!! performance.memory not supported !!!');
}
if (!performance.memory.usedJSHeapSize) {
return('!!! performance.memory.usedJSHeapSize not supported !!!');
}
return Math.round(performance.memory.usedJSHeapSize / 10000, 2) / 100 + ' MB';
}
function createArray(numOfRandomNumbers) {
var result = [];
for(var i=0; i<numOfRandomNumbers; i++) {
result.push(Math.random());
}
return result;
}
app.controller('Ctrl', function ($rootScope, $scope, constants) {
$scope.name = ($rootScope.controllerInstantiations % 2 == 0) ? 'This' : 'That';
$scope.controllerInstantiations = $rootScope.controllerInstantiations++;
$scope.heapSize = heapSize();
$scope.randomArray = createArray(constants.numOfRandomNumbers);
if (constants.shouldRegister) {
var unregister = $rootScope.$on('someEvent', function() {
$scope.eventOccurred = true;
});
if (constants.shouldUnregister) {
$scope.$on('$destroy', function() {
unregister();
});
}
}
});
app.config(function ($routeProvider) {
$routeProvider.when('/this', {
templateUrl: 'tab.html',
controller: 'Ctrl'
})
.when('/that', {
templateUrl: 'tab.html',
controller: 'Ctrl'
})
.otherwise({
redirectTo: '/this'
});
});
app.run(['$rootScope',
'$timeout', '$location', 'constants', function ($rootScope, $timeout, $location, constants) {
$rootScope.controllerInstantiations = 0;
$rootScope.autoSwitching = false;
function scheduleTabSwitch(autoSwitchTimeout) {
$rootScope.switchPromise = $timeout(function () {
var path =...