Fix a few memory leaks; add /gc console command
3 memory leaks were fixed - ipThrottle (due to the periodic cleaner clearing the wrong object...) - ipCount (shouldn't have leaked very much, but removing obsolete data is good practice) - lastguestlogin (again, shouldn't leak much, but should be cleared periodically anyways) A new console command (i.e. from the terminal running node) was added: /gc - If the process is invoked as node --expose-gc index.js, /gc allows you to manually invoke the garbage collector
This commit is contained in:
parent
e973813718
commit
04dbb3444b
|
@ -128,3 +128,8 @@ contacts:
|
||||||
- name: 'calzoneman'
|
- name: 'calzoneman'
|
||||||
title: 'Developer'
|
title: 'Developer'
|
||||||
email: 'cyzon@cytu.be'
|
email: 'cyzon@cytu.be'
|
||||||
|
|
||||||
|
# If set to true, when the ipThrottle and lastguestlogin rate limiters are cleared
|
||||||
|
# periodically, the garbage collector will be invoked immediately.
|
||||||
|
# The server must be invoked with node --expose-gc index.js for this to have any effect.
|
||||||
|
aggressive-gc: false
|
||||||
|
|
7
index.js
7
index.js
|
@ -40,5 +40,12 @@ function handleLine(line) {
|
||||||
if (line === "/reload") {
|
if (line === "/reload") {
|
||||||
Logger.syslog.log("Reloading config");
|
Logger.syslog.log("Reloading config");
|
||||||
Config.load("config.yaml");
|
Config.load("config.yaml");
|
||||||
|
} else if (line === "/gc") {
|
||||||
|
if (global && global.gc) {
|
||||||
|
Logger.syslog.log("Running GC");
|
||||||
|
global.gc();
|
||||||
|
} else {
|
||||||
|
Logger.syslog.log("Failed to invoke GC: node started without --expose-gc");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,17 +69,6 @@ function initPasswordResetCleanup(Server) {
|
||||||
}, CLEAN_INTERVAL);
|
}, CLEAN_INTERVAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clean out old rate limiters */
|
|
||||||
function initIpThrottleCleanup(Server) {
|
|
||||||
setInterval(function () {
|
|
||||||
for (var ip in Server.ipThrottle) {
|
|
||||||
if (Server.ipThrottle[ip].lastTime < Date.now() - 60 * 1000) {
|
|
||||||
delete Server.ipThrottle[ip];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, 5 * 60 * 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
function initChannelDumper(Server) {
|
function initChannelDumper(Server) {
|
||||||
var CHANNEL_SAVE_INTERVAL = parseInt(Config.get("channel-save-interval"))
|
var CHANNEL_SAVE_INTERVAL = parseInt(Config.get("channel-save-interval"))
|
||||||
* 60000;
|
* 60000;
|
||||||
|
@ -102,7 +91,6 @@ module.exports = function (Server) {
|
||||||
init = Server;
|
init = Server;
|
||||||
initStats(Server);
|
initStats(Server);
|
||||||
initAliasCleanup(Server);
|
initAliasCleanup(Server);
|
||||||
initIpThrottleCleanup(Server);
|
|
||||||
initChannelDumper(Server);
|
initChannelDumper(Server);
|
||||||
initPasswordResetCleanup(Server);
|
initPasswordResetCleanup(Server);
|
||||||
};
|
};
|
||||||
|
|
|
@ -86,7 +86,8 @@ var defaults = {
|
||||||
title: "Developer",
|
title: "Developer",
|
||||||
email: "cyzon@cytu.be"
|
email: "cyzon@cytu.be"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"aggressive-gc": false
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -12,7 +12,6 @@ var CONNECT_RATE = {
|
||||||
sustained: 0.1
|
sustained: 0.1
|
||||||
};
|
};
|
||||||
|
|
||||||
// Keep track of rate limiting by IP
|
|
||||||
var ipThrottle = {};
|
var ipThrottle = {};
|
||||||
// Keep track of number of connections per IP
|
// Keep track of number of connections per IP
|
||||||
var ipCount = {};
|
var ipCount = {};
|
||||||
|
@ -80,6 +79,10 @@ function handleConnection(sock) {
|
||||||
|
|
||||||
sock.on("disconnect", function () {
|
sock.on("disconnect", function () {
|
||||||
ipCount[ip]--;
|
ipCount[ip]--;
|
||||||
|
if (ipCount[ip] === 0) {
|
||||||
|
/* Clear out unnecessary counters to save memory */
|
||||||
|
delete ipCount[ip];
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!(ip in ipCount)) {
|
if (!(ip in ipCount)) {
|
||||||
|
@ -139,3 +142,21 @@ module.exports = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Clean out old rate limiters */
|
||||||
|
setInterval(function () {
|
||||||
|
for (var ip in ipThrottle) {
|
||||||
|
if (ipThrottle[ip].lastTime < Date.now() - 60 * 1000) {
|
||||||
|
var obj = ipThrottle[ip];
|
||||||
|
/* Not strictly necessary, but seems to help the GC out a bit */
|
||||||
|
for (var key in obj) {
|
||||||
|
delete obj[key];
|
||||||
|
}
|
||||||
|
delete ipThrottle[ip];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Config.get("aggressive-gc") && global && global.gc) {
|
||||||
|
global.gc();
|
||||||
|
}
|
||||||
|
}, 5 * 60 * 1000);
|
||||||
|
|
|
@ -9,7 +9,7 @@ The above copyright notice and this permission notice shall be included in all c
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const VERSION = "3.0.2";
|
const VERSION = "3.0.3";
|
||||||
var singleton = null;
|
var singleton = null;
|
||||||
var Config = require("./config");
|
var Config = require("./config");
|
||||||
|
|
||||||
|
|
15
lib/user.js
15
lib/user.js
|
@ -604,6 +604,21 @@ User.prototype.guestLogin = function (name) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Clean out old login throttlers to save memory */
|
||||||
|
setInterval(function () {
|
||||||
|
var delay = Config.get("guest-login-delay");
|
||||||
|
for (var ip in lastguestlogin) {
|
||||||
|
var diff = (Date.now() - lastguestlogin[ip]) / 1000;
|
||||||
|
if (diff > delay) {
|
||||||
|
delete lastguestlogin[ip];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Config.get("aggressive-gc") && global && global.gc) {
|
||||||
|
global.gc();
|
||||||
|
}
|
||||||
|
}, 5 * 60 * 1000);
|
||||||
|
|
||||||
User.prototype.initUserPLCallbacks = function () {
|
User.prototype.initUserPLCallbacks = function () {
|
||||||
require("./userplaylists").init(this);
|
require("./userplaylists").init(this);
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
"author": "Calvin Montgomery",
|
"author": "Calvin Montgomery",
|
||||||
"name": "CyTube",
|
"name": "CyTube",
|
||||||
"description": "Online media synchronizer and chat",
|
"description": "Online media synchronizer and chat",
|
||||||
"version": "3.0.2",
|
"version": "3.0.3",
|
||||||
"repository": {
|
"repository": {
|
||||||
"url": "http://github.com/calzoneman/sync"
|
"url": "http://github.com/calzoneman/sync"
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue