Home > Mobile >  Why JavaScript loops do not overflow stack?
Why JavaScript loops do not overflow stack?

Time:09-06

I've got a couple of questions about memory allocation in JavaScript

As far as I know, JavaScript primitives are immutable and stored in the stack. If we change the value of a primitive or if we assign a new variable to the old variable, it creates a new memory location for each case.

let x = 2 
let y = x
x = 3
console.log(y) // 2

  1. When we run a large loop just as the example bellow, 99999999 times 8bytes needed in stack to allocate space for i. So, why the stack is not overflown?
    for(let i = 0; i<99999999; i  ){
       let x = i
    }
  1. If millions of objects are created simultaneously (in a real world app), is the stack enough to hold references to all the objects in the heap?

CodePudding user response:

the key point here is that the code includes a garbage collector, once a memory allocation has been narked as not required, the GC is allowed to reallocated for a different use

this is a little oversimplified but lets looks at what's happening at each stage

let x = 3; //create a memory allocation in memory and alias x, store the value 3 in memory

let y = x; //create a memory allocation in memory and alias y, store the value located in memory under the alias x in it

x = 2; //save the value 2 in memory location x

so the stack never exceeds a single state that is scoped to 2 allocuted variables

for your loop example

for(let i = 0; i<99999999; i  ){ //
   let x = i
}
/*
create a memory allocation in memory and alias i, store the value 0 in it
create a code marker for the for loop
create a memory allocation in memory and alias x, store the value located in memory under the alias i in it
check if the value held in memory location i < 99999999

   yes 
        save the value i 1 in memory location i set execute point to the previous save marker
        mark memory location aliased x as not required

   no 
        unset execution marker
        mark memory location aliased x as not required
*/

here their may be some growth in the memory usage from the allocation of the x variable in the loop however GC can easily clean this up

now for the issue you haven't considered recursion

function doSomething(i){
    let x = doSomething(i);
    return x;
}
doSomething(i)
/*
create a code marker for the for function doSomething
create a state in the stack for doSomething
create a memory allocation in memory and alias i, store the value passed to do something in it

set passed value to value in i 
set current execution location to marker for to doSomething

*** will never happen because recursive calls never end ***
pop the previous code marker from the stack
set the return value in popped state to value in x
mark state as not required 
continue execution from popped code marker
       
*/

for this one every time you call the function doSomething the stack has an state added to it this state is a memory slot that stores the passed in value and any variables created in scope added to it when doSomething is completed this state is marked as no required however until the code can return the system has to keep allocating more and more room on the stack for each calls state this is why recursion is much less safe than normal loops

CodePudding user response:

As commenters have already said, there is no stack involved in your example, or at least not how you imagine there is.

If you want to break your stack, try this instead:

function Overflow(count){
    console.log('count:', count)
    return Overflow(count   1)
}

Overflow(0)
  • Related