> 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.