Stack – Why Does the Call Stack Have a Static Maximum Size?

stack

Having worked with a few programming languages, I've always wondered why the thread stack has a predefined maximum size, instead of expanding automatically as required. 

In comparison, certain very common high level structures (lists, maps, etc.) which are found in most programming languages are designed to grow as required while new elements are added, being limited in size only by available memory, or by computational limits (e.g. 32 bit addressing).

I'm not aware though of any programming languages or runtime environments where the maximum stack size isn't pre-limited by some default or compiler option.
This is why too much recursion will result very quickly in a ubiquitous stack overflow error/exception, even when only a minimal percentage of the memory available to a process is used for the stack.

Why is it the case that most (if not all) runtime environments set a maximum limit for the size a stack can grow at runtime?

Best Answer

It's possible to write an operating system that doesn't require stacks to be contiguous in address space. Basically you need some extra messing about in the calling convention, to ensure that:

  1. if there isn't enough space in the current stack extent for the function you're calling, then you create a new stack extent and move the stack pointer to point to the start of it as part of making the call.

  2. when you return from that call you transfer back to the original stack extent. Most likely you retain the one created at (1) for future use by the same thread. In principle you could release it, but that way lie rather inefficient cases where you keep hopping back and forth across the boundary in a loop, and every call requires memory allocation.

  3. setjmp and longjmp, or whatever equivalent your OS has for non-local transfer of control, are in on the act and can correctly move back to the old stack extent when required.

I say "calling convention" -- to be specific I think it's probably best done in a function prologue rather than by the caller, but my memory of this is hazy.

The reason that quite a few languages specify a fixed stack size for a thread, is that they want to work using the native stack, on OSes that don't do this. As everyone else's answers say, under the assumption that each stack needs to be contiguous in address space, and cannot be moved, you need to reserve a specific address range for use by each thread. That means choosing a size up front. Even if your address space is massive and the size you choose is really large, you still have to choose it as soon as you have two threads.

"Aha" you say, "what are these supposed OSes that use non-contiguous stacks? I bet it's some obscure academic system of no use to me!". Well, that's another question that fortunately is already asked and answered.