From f552f25171390e726ad7246ed18b994970bcf764 Mon Sep 17 00:00:00 2001 From: Igor Minar Date: Tue, 25 Mar 2014 23:04:21 -0700 Subject: [PATCH] fix(Scope): aggressively clean up scope on $destroy to minimize leaks Due to a known V8 memory leak[1] we need to perform extra cleanup to make it easier for GC to collect this scope object. The theory is that the V8 leaks are due to inline caches which are caches built on the fly to speed up property access for javascript objects. By cleaning the scope object and removing all properties, we clean up ICs as well and so no leaks occur. I was able to manually verify that this fixes the problem for the following example app: http://plnkr.co/edit/FrSw6SCEVODk02Ljo8se?p=preview Given the nature of the problem I'm not 100% sure that this will work around the V8 problem in scenarios common for Angular apps, but I guess it's better than nothing. [1] V8 bug: https://code.google.com/p/v8/issues/detail?id=2073 Closes #6794 Closes #6856 --- src/ng/rootScope.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/src/ng/rootScope.js b/src/ng/rootScope.js index e09e2202b78d..aec16298679b 100644 --- a/src/ng/rootScope.js +++ b/src/ng/rootScope.js @@ -731,15 +731,26 @@ function $RootScopeProvider(){ forEach(this.$$listenerCount, bind(null, decrementListenerCount, this)); + // sever all the references to parent scopes (after this cleanup, the current scope should + // not be retained by any of our references and should be eligible for garbage collection) if (parent.$$childHead == this) parent.$$childHead = this.$$nextSibling; if (parent.$$childTail == this) parent.$$childTail = this.$$prevSibling; if (this.$$prevSibling) this.$$prevSibling.$$nextSibling = this.$$nextSibling; if (this.$$nextSibling) this.$$nextSibling.$$prevSibling = this.$$prevSibling; - // This is bogus code that works around Chrome's GC leak - // see: https://github.com/angular/angular.js/issues/1313#issuecomment-10378451 - this.$parent = this.$$nextSibling = this.$$prevSibling = this.$$childHead = - this.$$childTail = null; + // This is bogus code that works around V8's memory leak coming from ICs + // see: https://code.google.com/p/v8/issues/detail?id=2073#c26 + // + // for more info also see: + // - https://github.com/angular/angular.js/issues/6794#issuecomment-38648909 + // - https://github.com/angular/angular.js/issues/1313#issuecomment-10378451 + for (var prop in this) { + if (hasOwnProperty.call(this, prop)) { + this[prop] = null; + } + } + // recreate the $$destroyed flag + this.$$destroyed = true; }, /**