← Back to context

Comment by simonask

2 days ago

The amount of stack you pay for on a thread is proportional to the maximum depth that the stack ever reached on the thread. Operating systems can grow the amount of real memory allocated to a thread, but never shrink it.

It’s a programming model that has some really risky drawbacks.

> Operating systems can grow the amount of real memory allocated to a thread, but never shrink it.

Operating systems can shrink the memory usage of a stack.

  madvise(page, size, MADV_DONTNEED);

Leaves the memory mapping intact but the kernel frees underlying resources. Subsequent accesses get either new zero pages or the original file's pages.

Linux also supports mremap, which is essentially a kernel version of realloc. Supports growing and shrinking memory mappings.

  stack = mremap(stack, old_size, old_size / 2, MREMAP_MAYMOVE, 0);

Whether existing systems make use of this is another matter entirely. My language uses mremap for growth and shrinkage of stacks. C programs can't do it because pointers to stack allocated objects may exist.

  • > C programs can't do it because pointers to stack allocated objects may exist.

    They sure shouldn't exist to the unused region of the stack though; if they do, that's a bug (because anything could claim that memory now). You should be free and clear to release stack pages past your current stack pointer.

    • High level languages have entire runtime systems dedicated to managing resources like that. My language can allocate, grow, shrink and deallocate stacks dynamically. It has complete visibility into everything, and the stacks themselves are designed to be relocatable and position-independent.

      In C it's impossible to even get the stack pointer without dropping to assembly or using compiler builtins. It's hard to know where the stack starts or even how big it is.

      1 reply →

    • There isn’t any operating system or compiler that does this today, and it probably isn’t worth it to pursue. Enlarging the stack via page fault is really expensive, so you would need really advanced heuristics to prevent repeatedly unmapping/remapping those pages.

      The correct tool for myriad of small tasks is coroutines / green threads / async tasks, so why spend any energy optimizing threads for that purpose instead of what they are already good at?

      1 reply →

  • Stack memory is never unmapped until the thread terminates as far as I know. I don’t know of any kernel that does this, for precisely the reason you arrive at by the very last sentence.

    • It's just normal pages to the kernel. In theory, it's totally possible for the program to munmap some of its own stack's pages if it was sophisticated enough. Typical C programs just aren't capable of it, at least not without great effort.