Skip to content

Commit b4fd43b

Browse files
committed
fix($rootScope): fix potential memory leak when removing scope listeners
When removing listeners the listener is removed from the array but the array size is not changed until the event is fired again. If that event is never fired but listeners are added/removed then this array will continue growing. This changes the listener removal to `delete` the array entry instead of setting it to `null` in the hope of the browser deallocating the memory for the array entry. Fixes angular#16135
1 parent 6b7505e commit b4fd43b

File tree

2 files changed

+19
-1
lines changed

2 files changed

+19
-1
lines changed

src/ng/rootScope.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -1180,7 +1180,10 @@ function $RootScopeProvider() {
11801180
return function() {
11811181
var indexOfListener = namedListeners.indexOf(listener);
11821182
if (indexOfListener !== -1) {
1183-
namedListeners[indexOfListener] = null;
1183+
// Use delete in the hope of the browser deallocating the memory for the array entry,
1184+
// while not shifting the array indexes of other listeners.
1185+
// See issue https://github.com/angular/angular.js/issues/16135
1186+
delete namedListeners[indexOfListener];
11841187
decrementListenerCount(self, 1, name);
11851188
}
11861189
};

test/ng/rootScopeSpec.js

+15
Original file line numberDiff line numberDiff line change
@@ -2316,6 +2316,21 @@ describe('Scope', function() {
23162316
}));
23172317

23182318

2319+
// See issue https://github.com/angular/angular.js/issues/16135
2320+
it('should deallocate the listener array entry', inject(function($rootScope) {
2321+
var remove1 = $rootScope.$on('abc', noop);
2322+
$rootScope.$on('abc', noop);
2323+
2324+
expect($rootScope.$$listeners['abc'].length).toBe(2);
2325+
expect(0 in $rootScope.$$listeners['abc']).toBe(true);
2326+
2327+
remove1();
2328+
2329+
expect($rootScope.$$listeners['abc'].length).toBe(2);
2330+
expect(0 in $rootScope.$$listeners['abc']).toBe(false);
2331+
}));
2332+
2333+
23192334
it('should call next listener when removing current', inject(function($rootScope) {
23202335
var remove1 = $rootScope.$on('abc', function() { remove1() });
23212336

0 commit comments

Comments
 (0)