Bug 1145049 - Cleanup inspector related actors to avoid leaking stuff if any actor is leaked. r=pbrosset
authorAlexandre Poirot <poirot.alex@gmail.com>
Mon, 14 Sep 2015 02:47:13 -0700
changeset 294869 c34db58fa00778f38d8872e65a8eb7a6e9f6162c
parent 294868 cf8240fca7de8f27a2efa028d426bed143d09fed
child 294870 9ad4faa7625508a8066e633a4e5a6298188035c3
push id5245
push userraliiev@mozilla.com
push dateThu, 29 Oct 2015 11:30:51 +0000
treeherdermozilla-beta@dac831dc1bd0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerspbrosset
bugs1145049
milestone43.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1145049 - Cleanup inspector related actors to avoid leaking stuff if any actor is leaked. r=pbrosset
toolkit/devtools/server/actors/inspector.js
toolkit/devtools/server/actors/styles.js
--- a/toolkit/devtools/server/actors/inspector.js
+++ b/toolkit/devtools/server/actors/inspector.js
@@ -1340,34 +1340,54 @@ var WalkerActor = protocol.ActorClass({
     // Allow native anon content (like <video> controls) if preffed on
     let nodeFilter = this.showAllAnonymousContent
                         ? allAnonymousContentTreeWalkerFilter
                         : standardTreeWalkerFilter;
     return new DocumentWalker(node, this.rootWin, whatToShow, nodeFilter);
   },
 
   destroy: function() {
+    if (this._destroyed) {
+      return;
+    }
+    this._destroyed = true;
+    protocol.Actor.prototype.destroy.call(this);
     try {
-      this._destroyed = true;
-
       this.clearPseudoClassLocks();
       this._activePseudoClassLocks = null;
 
       this._hoveredNode = null;
+      this.rootWin = null;
       this.rootDoc = null;
+      this.rootNode = null;
+      this.layoutHelpers = null;
+      this._orphaned = null;
+      this._retainedOrphans = null;
+      this._refMap = null;
+
+      events.off(this.tabActor, "will-navigate", this.onFrameUnload);
+      events.off(this.tabActor, "navigate", this.onFrameLoad);
+
+      this.onFrameLoad = null;
+      this.onFrameUnload = null;
 
       this.reflowObserver.off("reflows", this._onReflows);
       this.reflowObserver = null;
+      this._onReflows = null;
       releaseLayoutChangesObserver(this.tabActor);
 
+      this.onMutations = null;
+
+      this.tabActor = null;
+
       events.emit(this, "destroyed");
     } catch(e) {
       console.error(e);
     }
-    protocol.Actor.prototype.destroy.call(this);
+
   },
 
   release: method(function() {}, { release: true }),
 
   unmanage: function(actor) {
     if (actor instanceof NodeActor) {
       if (this._activePseudoClassLocks &&
           this._activePseudoClassLocks.has(actor)) {
@@ -3514,16 +3534,17 @@ var InspectorActor = exports.InspectorAc
   },
 
   destroy: function () {
     protocol.Actor.prototype.destroy.call(this);
     this._highlighterPromise = null;
     this._pageStylePromise = null;
     this._walkerPromise = null;
     this.walker = null;
+    this.tabActor = null;
   },
 
   // Forces destruction of the actor and all its children
   // like highlighter, walker and style actors.
   disconnect: function() {
     this.destroy();
   },
 
--- a/toolkit/devtools/server/actors/styles.js
+++ b/toolkit/devtools/server/actors/styles.js
@@ -148,16 +148,29 @@ let PageStyleActor = protocol.ActorClass
 
     // Stores the association of DOM objects -> actors
     this.refMap = new Map();
 
     this.onFrameUnload = this.onFrameUnload.bind(this);
     events.on(this.inspector.tabActor, "will-navigate", this.onFrameUnload);
   },
 
+  destroy: function () {
+    if (!this.walker) {
+      return;
+    }
+    protocol.Actor.prototype.destroy.call(this);
+    events.off(this.inspector.tabActor, "will-navigate", this.onFrameUnload);
+    this.inspector = null;
+    this.walker = null;
+    this.refMap = null;
+    this.cssLogic = null;
+    this._styleElement = null;
+  },
+
   get conn() {
     return this.inspector.conn;
   },
 
   form: function(detail) {
     if (detail === "actorid") {
       return this.actorID;
     }
@@ -1020,16 +1033,27 @@ let StyleRuleActor = protocol.ActorClass
       };
     }
   },
 
   get conn() {
     return this.pageStyle.conn;
   },
 
+  destroy: function () {
+    if (!this.rawStyle) {
+      return;
+    }
+    protocol.Actor.prototype.destroy.call(this);
+    this.rawStyle = null;
+    this.pageStyle = null;
+    this.rawNode = null;
+    this.rawRule = null;
+  },
+
   // Objects returned by this actor are owned by the PageStyleActor
   // to which this rule belongs.
   get marshallPool() {
     return this.pageStyle;
   },
 
   getDocument: function(sheet) {
     let document;