If a closure is a stack frame that is
allocated when a function starts its execution, and not freed after the function returns (as if a 'stack frame' were allocated on the heap rather than the stack!),
doesn't that mean that the stack could get fragmented?
For instance, foo() is called, and then bar() is called. Both are closures. Is there any scenario that would make foo()'s closure to get out of scope, or to otherwise be candidate for deallocation (where deallocation in the case of the stack merely means that the runtime will move the stack pointer back, releasing space) while bar() continues to require space on the stack?
If such an event happens repeatedly, then the equivalent of heap fragmentation would occur on the stack, except that by the very nature of how stacks work, the space would be lost. Evidently this doesn't happen. What stops it from happening?
I'm interested specifically in the context of JavaScript, where one doesn't have even a rough idea of the machine running the code, but the question applies for any functional language.
In an effort to make the question down-to-earth...
Consider the following code sample.
outer = function() {
var foo = function(v) {
return function() { return v; }
}
var bar = function(w) {
return function() { return w; }
}
var f = foo(5);
var b = bar(7);
document.writeln(f());
document.writeln(b());
document.writeln(f());
document.writeln(b());
}
outer();
Sequence of events: outer() is called. Its return address is saved on the stack. foo
, bar
, f
, and b
are all hoisted, and hence are allocated on the stack as soon as outer()
is called. foo()
is called with parameter 5
. The parameter to the function foo()
, like any local variable, also gets allocated on the stack. The function foo()
returns an anonymous function, also via the stack. The same pair of events occur for b
and bar
. I think that the anonymous function inside foo()
is the closure because it refers to a variable in the scope that encloses it, but never mind the semantics and what is a closure. My question is: How do we know that f
and foo()
could not get dealloated while b
and bar()
are alive, hence creating an empty and inaccessible stack fragment?