I have a function:
function test()
{
for( var i = 0; i < 1000000; i++ )
{
setTimeout( function()
{
//
}, 10000 );
}
}
Running this on chrome, it propels memory usage from around 50MB to 600MB, which I guess is ok; but after the timeouts have been executed, the garbage collector doesn't seem to remove them from memory, and it just stays at 600MB until I refresh, even then though it leaves some sort of "foot print" of 150MB after the page refresh.
Any idea how to tell the garbage collector to get rid of them after their execution?
You are correct that there appears to be memory that is never cleaned up. My best guess at the problem is that creating a function in a for loop like this creates a new scope which must have access to i. Therefore, those functions never get cleaned. I misspoke - the functions should definitely get cleaned up. Testing in my browser took the memory up over 900MB.
It's important to note that there is no benefit to doing what you are doing and it can be classified as "poor code" at best. You should create one function and reuse it:
// reusing a function fixes the problem
function test () {
var fn = function () {};
for (var i = 0; i < 1000000; i++) {
setTimeout(fn, 1000);
}
}
My observation was that memory usage shot back up over 900MB and then gradually fell back down to closer to normal over the course of a couple minutes.
If you are needing access to the variable i inside of your functions, I hate to say that your code will not give you that. You will only ever see the last value of i (1000000). If you are wanting to use i inside your functions, you can use a factory function. In my tests the memory eventually got cleaned up:
// using a factory fixes the problem and give you access to 'i'
function test () {
function factory (n) {
return function () {
/* This will get called later. 'n' will represent
the value of 'i' at the time this function was created */
}
}
for (var i = 0; i < 1000000; i++) {
setTimeout(factory(i), 1000);
}
};
Unfortunately, the memory problem persists if you use bind:
// Memory problem still exists with .bind
function test () {
var fn = function (n) { };
for (var i = 0; i < 1000000; i++) {
setTimeout(fn.bind(null, i), 1000);
}
}
As for the memory usage remaining high after a page refresh, this I cannot explain but it might have to do with the browser setting aside more memory for a tab which appears to be using a lot of memory. I dunno, just a guess.
Related
I have a function that loops an object from a MongoDB collection. It's all possible connections for some mail transportation posts. Once I get one connection, I want to immediately remove the inverse connection from the connections object, for example, postA=1 and postB=2, I want to remove postA=2 and postB=1 (removeConnection function does that).
I can't understand why it only returns one 'A' on the console when I try to run that function inside calculateRoute, and returns three 'A' (which is what it should) when I remove it. That function is somehow breaking the loop.
calculatedRoutes = calculateRoute(store.postid, client.postid, connections, []);
function calculateRoute(actualPost, finalPost, connections, routes) {
for(i=0; i < connections.length; i++) {
if(actualPost == connections[i].postA) {
console.log('A');
// If I remove this, the console shows A three times. If I keep this, only shows 1 time.
connections = removeConnection(connections[i].postB, connections[i].postA, connections);
}
}
return routes;
}
function removeConnection(postA, postB, connections) {
for(i=0; i < connections.length; i++) {
if(connections[i].postA == postA && connections[i].postB == postB) {
delete connections[i];
//break;
}
}
return connections;
}
It appears that you are modifying the collection that you are iterating over when you callremoveConnection. I would venture to say that after the first loop, connections.length is less than your loop control variable, which would cause the loop to terminate. What are the contents of connections after the function call?
In general, directly modifying a collection you're iterating over is bad practice. A better option would be to project the collection into a new one that contains the values you want (using map,filter,etc). That way your not mutating anything.
Fixed it by adding var to i=0 on each for. Can someone explain?
for(var i=0; i < connections.length; i++) {...
First, please excuse my bad English. I'm not use to write in English.
I'm using Node.js and i have variables that sometimes get their value from async functions and sometimes by direct assignment (ex:
async(function(data) {
var x= data.something
}; or x = 5;)
the problem is that later on the have shared code which forces me to duplicate the code.
in syncronius scripting i usually do an if.. else statement to seperate the cases and assign. ex:
if(boolivar){
var x = niceFunc();
}
else {
var x = 5;
}
coolFunc(x);
now days im forced to to this:
if(boolivar){
niceFUnc(function(X){
coolFunc(X);
}
}
else{
var x = 5;
coolFunc(X);
}
does someone has an idea how to solve my problem?
I thought about forcing the async function to be sync but:
a. i dont know how
b. it kind of ruins the whole point
I would do it essentially as you have, except that I would abstract the sync/async calls so that it doesn't make any difference to the code that's using it what's really happening behind the scenes (ignore the bad function names; I have no idea what your code does):
function doNiceFunc(boolivar, callback) {
if (boolivar) {
niceFUnc(function(x) {
callback(x);
});
} else {
callback(5);
}
}
Now doNiceFunc appears the same in both cases from the outside:
doNiceFunc(boolivar, function(x) {
coolFunc(x);
});
I've used this exact pattern in a library that retrieved data that was sometimes immediately available and other times had to be retrieved from the network. The users of this library didn't have to care which was the case at any given time, because the call looked the same in both situations.
I tend to use this lib node-sync
var sync = require('sync');
sync(function(){
var result = query.sync(query, params);
// result can be used immediately
})
I am not entirely sure how to phrase this question, but basically, I have a class, button that on its click should call the function passed to it.
button = function(...,callBack) {
//...
this._cb = callBack;
}
button.prototype.callBack = function(e) {
//...
this._cb();
}
and then somewhere else
//on canvas click
e.target.callBack(e);
(I hope this is about the right amount of background, I can give more if needed)
So the issue I am running into is when I dynamically instantiate the buttons such that their callbacks use data from an array. i.e.
for (var i = 0; i < levels.length; i++) {
buttons[buttons.length] = new button(..., function() {drawLevel(levels[i])});
}
Then when they are clicked, they run that callback code and try to find some random value for i (probably a for-loop that didn't use var) and runs that level.
My question is, how can I (without using eval) circumvent this problem.
Thanks!
I'm not 100% clear on what you're asking, but it looks like you're going to be getting the wrong value for i in the anonymous function you're creating in the loop (it will always be levels.length)
Way around this is to have a different scope for every function created, with the i in each scope being a copy of the i in the loop
buttons[buttons.length] = new button(..., (function(i){
return function() {drawLevel(levels[i])};
})(i));
I was reviewing the slides in this presentation: http://slid.es/gruizdevilla/memory
and on one of the slides, this code is presented with the suggestion that it creates a memory leak:
var buggyObject = {
callAgain: function() {
var ref = this;
var val = setTimeout(function() {
ref.callAgain();
}, 1000);
}
}
buggyObject.callAgain();
buggyObject = null;
Can someone explain the issue in more detail here? I might be missing some subtleties here.
This is definitely a memory leak. However, the memory consumption is so small and cannot be measured. I did some small changes to the source code.
I put the entire code inside a loop to create the same scenario 100,000 times
I increased the timer interval to about 16 minutes. This prevents browser from crashing
Here is the code:
for (var i = 0; i < 100000; i++) {
var buggyObject = {
callAgain: function() {
var ref = this;
var val = setTimeout(function() {
ref.callAgain();
}, 1000000); //16m
}
}
buggyObject.callAgain();
buggyObject = null;
}
My experiment:
I ran the code in Chrome Version 34.0.1847.116 m and captured memory changes using Developer Tools\Timeline.
As we can see in the picture, around 32 MB of memory has been consumed for running this code and after a while it's been decreased to about 30 MB and stayed unchanged (see #1).
After several garbage collecting attempts by Chrome (see #2) and one manual forced garbage collection by me (see #3, #4), the memory consumption remains unchanged.
There is no more buggyObject and there is nothing we can do to release the memory. The only possible way is to close the browser.
What causes this?
The main reason for this behavior is the timer. Timer callback and its tied object, buggyObject will not be released until the timeout happens. In our case timer resets itself and runs forever and therefore its memory space will never be collected even if there is no reference to the original object.
There is another question that describes how setTimeout() looks like it has memory leaks, but in reality does not.
However, I think what the author is trying to say is that since buggyObject creates a setTimeout which calls itself, even if you change buggyObject to equal null (saying you are done with the object and it can be cleaned up), the object won't be garbage collected because there is still a reference to it in the setTimeout(). This is technically a memory leak because there is no longer any direct reference to the setTimeout function so that you could clear it later (kind of a zombie timeout if you will).
As advncd pointed out, the timer gets executed and adds even more data on the stack. There is a conceptual view of what happens:
var a = 123;
// call the setTimeout.function
var a = 123;
// call the setTimeout.function
var a = 123;
// call the setTimeout.function
var a = 123;
// call the setTimeout.function
var a = 123;
// call the setTimeout.function
var a = 123;
// call the setTimeout.function
var a = 123;
// call the setTimeout.function
var a = 123;
// call the setTimeout.function
var a = 123;
...etc...
So each time a new variable a is allocated on the stack which grows forever.
What advncd did not mention, though, is the fact that you have a setInterval() function to do what you need to do: have the same function called over and over again. Now you still have a "memory leak" but only the initialization parameters leak (i.e. it won't grow each time the timer times out.)
So conceptually, the calls are flat and you avoid the leak:
a = 123;
// call the setTimeout.function
// call the setTimeout.function
// call the setTimeout.function
// call the setTimeout.function
// call the setTimeout.function
// call the setTimeout.function
// call the setTimeout.function
...etc...
I'm using a socket.io listener within one of my functions to listen for a "loser" event to tell the client that the other client won. However, I can't use the "this" keyword to talk about my client while inside the socket.on function as this refers to the socket itself. Am I going about this the wrong way? Or can access the client object some other way, like super?
socket.on('loser', function() {
//Remove all current objects then restart the game.
//THIS PART DOESN'T WORK, SINCE 'THIS' NO LONGER REFERS TO
//THE GAME OBJECT, BUT INSTEAD REFERENCES THE SOCKET LISTENER.
for(var i = 0; i < this.board.objects.length; i++)
{
this.board.remove(this.board.objects[i]);
}
//WORKS AS EXPECTED FROM HERE ON...
Game.setBoard(1, new TitleScreen(gameType,
"Loser!",
"Press Space to Play Again",
playGame));
});
Functions don't carry any information about the objects that reference them, you can use .bind() to bind the function to your object before you pass it:
socket.on('loser', function() {
//Remove all current objects then restart the game.
//THIS PART DOESN'T WORK, SINCE 'THIS' NO LONGER REFERS TO
//THE GAME OBJECT, BUT INSTEAD REFERENCES THE SOCKET LISTENER.
for (var i = 0; i < this.board.objects.length; i++) {
this.board.remove(this.board.objects[i]);
}
//WORKS AS EXPECTED FROM HERE ON...
Game.setBoard(1, new TitleScreen(gameType, "Loser!", "Press Space to Play Again",
playGame));
}.bind(this));
In browser-land the common way to do this is to set a variable like var that = this; before you enter the function, and then use that instead.
However, ECMAScript5 brought in bind(), which allows you to prevent the value of this being lost. In NodeJS of course, it's safe to use this (unlike in browser-land, where you have to support older browsers).
socket.on('loser', (function() {
//Remove all current objects then restart the game.
for (var i = 0; i < this.board.objects.length; i++) {
this.board.remove(this.board.objects[i]);
}
//WORKS AS EXPECTED FROM HERE ON...
Game.setBoard(1, new TitleScreen(gameType, "Loser!", "Press Space to Play Again", playGame));
}).bind(this));
For more info, see https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind
Whats wrong with something like this?
var self = this;
socket.on('loser', (function() {
//Remove all current objects then restart the game.
for (var i = 0; i < self.board.objects.length; i++) {
self.board.remove(self.board.objects[i]);
}
}