From ba54848db57662102da3cab9190f7b2c96003dea Mon Sep 17 00:00:00 2001 From: calzoneman Date: Sat, 30 Jan 2016 19:42:55 -0800 Subject: [PATCH] mediarefresher: fix memory leak from dangling timers --- src/channel/mediarefresher.js | 15 ++++++++++++++- src/server.js | 18 ++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/channel/mediarefresher.js b/src/channel/mediarefresher.js index a08b39b1..411d0512 100644 --- a/src/channel/mediarefresher.js +++ b/src/channel/mediarefresher.js @@ -44,6 +44,15 @@ MediaRefresherModule.prototype.onPreMediaChange = function (data, cb) { } }; +MediaRefresherModule.prototype.unload = function () { + try { + clearInterval(this._interval); + this._interval = null; + } catch (error) { + Logger.errlog.log(error.stack); + } +}; + MediaRefresherModule.prototype.initGoogleDocs = function (data, cb) { var self = this; self.refreshGoogleDocs(data, cb); @@ -66,8 +75,10 @@ MediaRefresherModule.prototype.initVimeo = function (data, cb) { const self = this; self.channel.refCounter.ref("MediaRefresherModule::initVimeo"); Vimeo.extract(data.id).then(function (direct) { - if (self.dead || self.channel.dead) + if (self.dead || self.channel.dead) { + self.unload(); return; + } if (self._media === data) { data.meta.direct = direct; @@ -88,6 +99,7 @@ MediaRefresherModule.prototype.refreshGoogleDocs = function (media, cb) { var self = this; if (self.dead || self.channel.dead) { + self.unload(); return; } @@ -153,6 +165,7 @@ MediaRefresherModule.prototype.initGooglePlus = function (media, cb) { var self = this; if (self.dead || self.channel.dead) { + self.unload(); return; } diff --git a/src/server.js b/src/server.js index 290e9b29..795efece 100644 --- a/src/server.js +++ b/src/server.js @@ -195,6 +195,24 @@ Server.prototype.unloadChannel = function (chan) { chan.notifyModules("unload", []); Object.keys(chan.modules).forEach(function (k) { chan.modules[k].dead = true; + /* + * Automatically clean up any timeouts/intervals assigned + * to properties of channel modules. Prevents a memory leak + * in case of forgetting to clear the timer on the "unload" + * module event. + */ + Object.keys(chan.modules[k]).forEach(function (prop) { + if (chan.modules[k][prop] && chan.modules[k][prop]._onTimeout) { + Logger.errlog.log("Warning: detected non-null timer when unloading " + + "module " + k + ": " + prop); + try { + clearTimeout(chan.modules[k][prop]); + clearInterval(chan.modules[k][prop]); + } catch (error) { + Logger.errlog.log(error.stack); + } + } + }); }); for (var i = 0; i < this.channels.length; i++) {