Understanding javascript closures and memory usage - javascript

EDIT: This is just a simple example to demontrate the concern I have with a much larger program. I wouldn't use this actual code for anything :)
If I run this -
<!DOCTYPE html>
<html>
<head>
<script>
function update(amount, win, data)
{
win.innerText = 'Count is ' + amount;
setTimeout(function() { update(amount + 1, win, {data: 'something'})}, 1000);
}
window.onload = function() {
var win = document.getElementById('item');
update(0, win, 0);
}
</script>
</head>
<body>
<div id="item"></div>
</body>
</html>
The call to setTimeout presumably creates a closure which captures the contents of the parameters to the "update" function (amount, win, data). So those variables are maintained in memory until the timeout is called and returns so that they will be available inside that function call...
But that function creates a new closure for the next iteration of the timeout... What will be captured in that second closure? Is it just the new copies of those variables or will the ones that formed part of the function call be captured again in the new closure?
Basically will this eventually run out of memory due to the data in each closure getting bigger and bigger, or is this safe and reasonable?

In my understanding, when a closure is created, the current lexical context is bundled with it. In your case, it would be the amount, win, data.
This context will be used, when the timeout fires, to execute the closure and thus call once again the function update; this call, although it might appear so, is not recursive, because the previous execution of update already ended and its original context (dynamic, which is different from the lexical one) has already been freed. (I think this is important to notice, because it seems you are worrying about a sort of stack growth due to recursion).
So, again, update is executed a second time and again a timeout is set and a closure created. This closure is bundled with the current lexical context of execution (which still includes just amount, win, data) and scheduled with the timer. then update finishes and removed from the stack. then again the timer fires and update is called again...
So, you should not worry about an unlimited growth of the context, for two reasons: first, only the lexical context is bundled with the closure; the call is not actually recursive.

A new closure is created every time the timeout callback is called, as you correctly say. But once the callback has been executed, there is no longer anything referencing the previous closure, so it can be garbage collected.

Related

Safe code in javascript How it handles the global execution context

This might be a silly question but most of the frameworks start with
(function(){
//all data
})()
Immediately invoked expression
So that There will be no collision with other js files right,so basically this is a function execution context that gets popped of the stack after execution,
but how come it still could handle asynchronous requests like a click after page has been loaded
For example:
(function(){
//all data
var a=true;
btn.addEventListener("click",()=>{
alert(a);
});
})() ;
The whole code runs first and an event Listener is given to a button but after,that execution context is popped off the stack so how come my button can still contact and get data from the "finished safecode function"?
Is this an implementation of closures where execution stack gets popped off but still the variables needed for dependant nested functions getting hung up?
Yeah, that's just the behavior of closures: a function always has access to everything declared in its outer blocks (lexical scope), even if the outer blocks have already finished execution. Until those functions don't exist anymore, the variables will continue to exist.
Inner functions keep a reference of their parents execution context

Javascript stack and recursive calls

Assume the following method(Just curious, I'm hopefully fail in js)
foo(0);
function foo(i){
if(i<1000){
setTimeout(function(){foo(i+1);}, 1000);
}
alert('I am foo');
}
So if I got it true, it should alerts around 1000 I am foos after 1000 seconds.
So doesn't it bother the browser about keeping the is in a sort of big stack? it should be too much I think or I'm wrong?
Yes, you will alert 1000 "foo" messages with this code.
However, the browser will not get bothered by the amount of i variables. i is a local variable to foo and as a result, it is only kept around as long as foo is executing. Each time the setTimeout callback is finished executing, i and the entire function's footprint is eligible for garbage collection by the browser (which will happen at an opportune time).
The reason for this is that there is no preserved memory call stack here because of the use of setTimeout. setTimeout does not do anything with a returned value from foo and as a result there are no pointers in memory keeping that function nor its variable environment from being collected.
Your call stack will look like this as your code goes through it's loop:
main() [local foo]
main() -> foo [local i = 0]
main()
(empty)
setTimeout()
setTimeout() -> foo [local i = 1]
setTimeout()
(empty)
setTimeout()
setTimeout() -> foo [local i = 2]
setTimeout()
(empty)
over and over until i equals 1000.
It happens this way because setTimeout is a browser api that waits n amount of time and then inserts the callback into the callback queue. The callback will then get picked up by the event loop and executed when the callstack is empty.
So, no, you aren't in any danger of overloading the browser with stacks or vars or whatever you were worried about. Your callstack will remain small because each time foo is executed, it fires off a setTimeout and returns. the i will stay in memory until the setTimeout's callback gets executed, at which point a new i will be created within the scope created by executing foo. That new i will stay in memory until the next setTimeout executes, on and on.
Here's a video that may help explain how this works. http://www.youtube.com/watch?v=8aGhZQkoFbQ
Firstly in javascript there is no "int" you have to say var i. And it gets alone the type for the declaration. If you want get Information about stack. You can use the debug console. And navigate to the call stacks. Its a nice feature you have also a nice overview. I prefer the Chromes Debugger. You can get there with pressing F12
1000 is in a stack is not a really big size for a browser to deal with.
Moreover, there won't be more than 2 is at the same time (maybe even only one), with each function executing every second.
This code won't load 1000 calls to get triggered with an interval of 1 second, this will chain calls, preventing the stack to get bloated.

Referencing parent scope in function, probability of leak?

When referencing a parent variable in a setInterval, do this can provoke a leak as I'm referencing self ?
var A = {};
A.act = function(a_var) {
var self = this;
self.a_var = a_var;
setInterval(function() {
console.log(self.a_var);
}, 100)
}
A.act();
Well, there's a leak in the sense that you start an interval timer running that you cannot stop without leaving the page (since you don't keep the handle). That means that the context of the call to act that created the timer, the timer callback, and A can never be GC'd, because the browser has a reference to the callback in its timer list, and the callback closes over the context of the call that created it. But I'm assuming that's desired behavior, so not really a leak.
In theory, the a_var argument is referenced by the closure (indirectly, by referencing the binding object of the execution context of the call to act), and so sticks around in memory even though you don't use it (you use self.a_var instead).
In practice (which is to say, allowing for implementation optimizations), it's complicated. Modern engines can optimize out variables and such that they know a closure doesn't access, but surprisingly simple things can disturb that process (at least on V8). This other question and answer have more on that.

javascript interval memory leak

I am reading this article on javascript optimization. Article
I came across this section and it tells me when a leak occurs. But I can't find what is the proper way to call it so a leak does not occur. Here is the section I am interested in.
One of the worst places to leak is in a loop, or in setTimeout()/setInterval(), but this is quite common.
Consider the following example.
var myObj = {
callMeMaybe: function () {
var myRef = this;
var val = setTimeout(function () {
console.log('Time is running out!');
myRef.callMeMaybe();
}, 1000);
}
};
If we then run:
myObj.callMeMaybe();
to begin the timer, we can see every second “Time is running out!” If we then run:
myObj = null;
The timer will still fire. myObj won’t be garbage collected as the closure passed to setTimeout has to be kept alive in order to be executed. In turn, it holds references to myObj as it captures myRef. This would be the same if we’d passed the closure to any other function, keeping references to it.
It is also worth keeping in mind that references inside a setTimeout/setInterval call, such as functions, will need to execute and complete before they can be garbage collected.
The question is: How do you do this properly so that you don't leak? Is it as simple as calling clearInterval? And does this leak once or leak once per interval
I wouldn't call this a memory leak in any fashion - it's simple garbage collection doing what it's supposed to. There is no more "proper" way to do it.
The object that was initially pointed to by myObj is still in use as long as your timer is running. A garbage collector will free it as soon as there are no more references to it. Setting myObj = null clears one reference to it, but your ongoing timers have another reference in myRef so it can not be garbage collected until ALL references to it are gone.
Yes, if you stop your timer and set myObj = null, then there will be no more references to the object and the GC will get rid of it. Keep in mind that you will need to provide access to the timerid if you want to stop the timer from the outside because no outside code can get to val where you have it stored now.
If you had lots of other data in myObj that the timer did not need access to and you were trying to allow that data to be freed while the timer continues to run, then you can either keep the same structure you have now, but clear that other data from the object (either remove the properties or set the properties to null) or you can change the structure of your code so that the recurring timer is launched with a separate function call and doesn't have to keep a reference to the object in order to call a method.
In other words, if your timer method needs access to the object, then the object is correctly kept alive by the garbage collector. If the timer method doesn't need access to the object, then you should run the recurring timer some other way that doesn't repeatedly call a method on the object - allowing the object to be garbage collected.

Using JavaScript closures in setTimeout

I'm using setTimeout to emulate rendering, and I came to the structure like this:
var Renderer = new Class (
{
Implements: Events,
initialize()
{
this.onRender();
},
onRender: function()
{
// some rendering actions
setTimeout(this.onRender.bind(this), 20);
}
});
Does that code have potential memory leaks because of infinite nesting of closures? Or everything is ok? The only solution I came so far is to rewrite it to usual
function Renderer()
{
var onRender = function()
{
// rendering
setTimeout(onRender, 20);
};
onRender();
};
But I don't want to lose Mootools Events and Classes.
For some reasons I can't use a "singleton" (like window.renderer = new Renderer();) too
Your code is fine, but Andy's answer is misleading because it confuses the scope chain with execution context and, by extension, call stack.
First, setTimeout functions do not execute in the global scope. They still execute in a closure and can access variables from outer scopes. This is because JavaScript uses static scope; that is, the scope chain of a function is defined at the moment that function is created and never changes; the scope chain is a property of the function.
Execution context is different and separate from the scope chain in that it is constructed at the time a function is invoked (whether directly – func(); – or as the result of a browser invocation, such as a timeout expiring). The execution context is composed of the activation object (the function's parameters and local variables), a reference to the scope chain, and the value of this.
The call stack can be thought of as an array of execution contexts. At the bottom of the stack is the global execution context. Each time a function is called, its parameters and this value are stored in a new 'object' on the stack.
If we were to change your onRender function to simply call itself (this.onRender()), the stack would quickly overflow. This is because control would never leave each successive onRender function, allowing its execution context to be popped off the call stack. Instead, we go deeper and deeper with each onRender waiting for the next onRender to return, in an infinite cycle broken only when the stack overflows.
However, with a call to setTimeout, control returns immediately and thus is able to leave the onRender function, causing its execution context to be popped off the stack and discarded (to be freed from memory by the GC).
When the timeout expires, the browser initiates a call to onRender from the global execution context; the call stack is only two deep. There is a new execution context – which by default would inherit the global scope as its this value; that's why you have to bind to your Renderer object – but it still includes the original scope chain that was created when you first defined onRender.
As you can see, you're not creating infinite closures by recursion because closures (scope chains) are created at function definition, not at function invocation. Furthermore, you're not creating infinite execution contexts because they are discarded after onRender returns.
We can make sure you're not leaking memory by testing it. I let it run 500,000 times and didn't observe any leaking memory. Note that the maximum call stack size is around 1,000 (varies by browser), so it's definitely not recursing.

Categories

Resources