One limitation of the stack is that it needs to be contiguous virtual addresses, so it was often limited when devices just didn't have the virtual address space to "waste" on a large stack for every thread in a process.

But 64 bits of virtual address space is large enough that you can keep the stacks far enough apart that even for pretty extreme numbers of threads you'll run out of physical memory before they start clashing. So you can always just allocate more physical pages to the stack as needed, similar to the heap.

I don't know if the .net runtime actually does this, though.

> So you can always just allocate more physical pages to the stack as needed, similar to the heap.

You set the (max) stack size once when you create the thread and you can’t increase the (max) size after that.

Processes see a virtual address space that is handled by the OS, so you would have to involve the OS if you needed to add to the stack size dynamically.

After process start and it's initial state, the stack is just another virtual address and the just sp another register. It can be mapped, remapped, changed to point to whatever. With overcommit even the initial state may not be entirely backed by physical pages.

Many userspace apps already do custom stack handling, it's how things like green threads work. And many non-native runtimes like .net already have custom handling for their managed stacks, as they often have different requirements and limitations to the "native" stack, and often incompatible formats and trying to isolate from possible bugs means there's less benefit to sharing the same stack with "native" code.

[dead]