-
Notifications
You must be signed in to change notification settings - Fork 7.3k
Timer.unref() memory leak #8364
Comments
Confirmed. Simplest example: var iter = 3e6;
(function runner() {
if (--iter < 0)
return;
setTimeout(function() { }, 0).unref();
setImmediate(runner);
}()); Output:
Remove the Ran my test on v0.12. So still exists. |
So running @trevnorris's test case and grabbing a core file from it, I was able to see that we had stable counts of the JS instantiated
looking briefly through, we don't seem to have the case covered where the C++ class's destructor is called that we're cleaning up the rest of the v8 memory, so the persistent is never being disposed. Here's a quick fix, that I think should solve your problem: diff --git a/lib/timers.js b/lib/timers.js
index be39ea6..694d5ce 100644
--- a/lib/timers.js
+++ b/lib/timers.js
@@ -303,7 +303,15 @@ Timeout.prototype.unref = function() {
if (delay < 0) delay = 0;
exports.unenroll(this);
this._handle = new Timer();
- this._handle.ontimeout = this._onTimeout;
+
+ var self = this;
+
+ this._handle.ontimeout = function closeIfTimeout() {
+ self._onTimeout();
+ if (!self.repeat)
+ self.close();
+ };
+
this._handle.start(delay, 0);
this._handle.domain = this.domain;
this._handle.unref(); please apply that to the v0.10 branch and let me know if it solves your problem |
In order to prevent any unnecessary function wrapping, here's a similar patch for v0.12: diff --git a/lib/timers.js b/lib/timers.js
index 3039b49..d8554ca 100644
--- a/lib/timers.js
+++ b/lib/timers.js
@@ -315,6 +315,14 @@ var Timeout = function(after) {
this._repeat = false;
};
+
+function unrefdHandle() {
+ this.owner._onTimeout();
+ if (!this.owner.repeat)
+ this.owner.close();
+}
+
+
Timeout.prototype.unref = function() {
if (!this._handle) {
var now = Timer.now();
@@ -323,7 +331,8 @@ Timeout.prototype.unref = function() {
if (delay < 0) delay = 0;
exports.unenroll(this);
this._handle = new Timer();
- this._handle[kOnTimeout] = this._onTimeout;
+ this._handle.owner = this;
+ this._handle[kOnTimeout] = unrefdHandle;
this._handle.start(delay, 0);
this._handle.domain = this.domain;
this._handle.unref(); |
I've just tested that, the patch fixes it. Thanks. |
cc @trevnorris let's land it. |
was this ever landed? |
@aheckmann it doesn't appear so. |
The destructor isn't being called for timers that have been unref'd. Fixes: #8364 Signed-off-by: Trevor Norris <trev.norris@gmail.com>
Fixed in v0.10 by 0d05123. |
The destructor isn't being called for timers that have been unref'd. Fixes: nodejs#8364 Signed-off-by: Trevor Norris <trev.norris@gmail.com>
The destructor isn't being called for timers that have been unref'd. Fixes: nodejs/node-v0.x-archive#8364
The destructor isn't being called for timers that have been unref'd. Fixes: nodejs/node-v0.x-archive#8364
The destructor isn't being called for timers that have been unref'd. Fixes: nodejs/node-v0.x-archive#8364 PR-URL: #1330 Reviewed-By: Fedor Indutny <fedor@indutny.com> Reviewed-By: Jeremiah Senkpiel <fishrock123@rocketmail.com>
Consider this code:
To reproduce the issue, start the script with
node script.js --unref
. Heap snapshot taken after few minutes of running the script:There are thousands of Timers leaking memory:
And this is a heap snapshot taken from the version without unref (
node script.js
):This is a hourly report from our app that uses
unref
frequently:OSX 10.9.4 & Debian 7.6
Node 0.10.31
The text was updated successfully, but these errors were encountered: