Don't forget about stack! For heavily multi-threaded processes on Linux, stack is usually the
biggest user of virtual memory.
As an aside, I know some operating systems use a "guard page" stack implementation, where
writes into the first page off the bottom (top?) of the stack trigger a page fault, which
allocates another page worth of real memory, and also moves the "guard page". The benefit
being that virtual memory use is much closer to actual memory use, and turning off overcommit
is much more viable. The downside is that the ABI requires the compiler to generate code to
probe every page when it needs to allocate a stack frame larger than the page size. Which
ironically can end up using more real memory than Linux's virtual-memory-hungry approach.