enter image description here

I have created the above picture to illustrate my question.

Is there a section within memory (lets say from address 0x1 to 0x15) that all processes use to place their text segment in (left figure), or each process gets a random location in memory to use for it's combination of heap, stack , text and data(right figure)?

  • On which operating system? Such details matter! Commented Feb 2, 2019 at 12:53

3 Answers 3


Modern Operating Systems tend to deduplicate memory at the page level. The idea is that the data and text segments may be copy-on-write shared (or just straight shared if the pages are not writable) between processes.

There is a good chance that “real” memory will not be contiguous or flow linearly at all, and that the virtual address space of each process will look exactly as you describe in the rightmost picture, with the caveat that the actual physical pages backing the virtual pages in a process may be shared with another process.

Also, Address Space Layout Randomization means that the various segments themselves may live at randomized locations with very very large distances between them (especially for 64 bit machines where there the address space is truly huge).

Finally remember that a process may have several threads, which all have their own stacks. So you would actually see multiple stacks floating around in each address space of the processes.


The right picture is more correct (but in practice, things are more complex), at least for Linux (and probably for other usual OSes, including MacOSX, Windows, other Unixes, Android, ...). The left picture is more relevant for single-address space operating systems (practically uncommon in 2019).

I recommend reading Operating Systems: Three Easy Pieces at first. The notion of virtual address space, and of processes, is tricky (but well explained there). ASLR is making things more complex.

Then, on Linux, read about proc(5) and use the /proc/ pseudo-file systems. Run the cat /proc/$$/maps and cat /proc/self/maps commands in a terminal, and understand their output. Do the same (and use also pmap(1)) on a multi-threaded process: every thread has its own call stack. Read some pthread tutorial for more.

In practice, with dynamic linking and shared objects, a virtual address space has "many" segments, since most shared libraries bring both their data and their text segment. For details on Linux, read Drepper's paper How to write shared libraries.

On my Linux/Debian, cat /proc/self/maps displays the virtual address space of the process running that very cat command. It shows:

559d55f71000-559d55f73000 r--p 00000000 08:01 5111854            /bin/cat
559d55f73000-559d55f78000 r-xp 00002000 08:01 5111854            /bin/cat
559d55f78000-559d55f7a000 r--p 00007000 08:01 5111854            /bin/cat
559d55f7b000-559d55f7c000 r--p 00009000 08:01 5111854            /bin/cat
559d55f7c000-559d55f7d000 rw-p 0000a000 08:01 5111854            /bin/cat
559d564a5000-559d564c6000 rw-p 00000000 00:00 0          [heap]
7fec9a3df000-7fec9a411000 r--p 00000000 08:01 11295313           /usr/lib/locale/C.UTF-8/LC_CTYPE
7fec9a411000-7fec9a584000 r--p 00000000 08:01 11295312           /usr/lib/locale/C.UTF-8/LC_COLLATE
7fec9a584000-7fec9ae03000 r--p 00000000 08:01 11272726           /usr/lib/locale/locale-archive
7fec9ae03000-7fec9ae25000 r--p 00000000 08:01 1710561            /lib/x86_64-linux-gnu/libc-2.28.so
7fec9ae25000-7fec9af6d000 r-xp 00022000 08:01 1710561            /lib/x86_64-linux-gnu/libc-2.28.so
7fec9af6d000-7fec9afb9000 r--p 0016a000 08:01 1710561            /lib/x86_64-linux-gnu/libc-2.28.so
7fec9afb9000-7fec9afba000 ---p 001b6000 08:01 1710561            /lib/x86_64-linux-gnu/libc-2.28.so
7fec9afba000-7fec9afbe000 r--p 001b6000 08:01 1710561            /lib/x86_64-linux-gnu/libc-2.28.so
7fec9afbe000-7fec9afc0000 rw-p 001ba000 08:01 1710561            /lib/x86_64-linux-gnu/libc-2.28.so
7fec9afc0000-7fec9afc4000 rw-p 00000000 00:00 0 
7fec9afc4000-7fec9afc6000 rw-p 00000000 00:00 0 
7fec9afd0000-7fec9aff2000 rw-p 00000000 00:00 0 
7fec9aff2000-7fec9aff3000 r--p 00000000 08:01 11302810           /usr/lib/locale/C.UTF-8/LC_NUMERIC
7fec9aff3000-7fec9aff4000 r--p 00000000 08:01 11303137           /usr/lib/locale/C.UTF-8/LC_TIME
7fec9aff4000-7fec9aff5000 r--p 00000000 08:01 11302043           /usr/lib/locale/C.UTF-8/LC_MONETARY
7fec9aff5000-7fec9aff6000 r--p 00000000 08:01 11300270           /usr/lib/locale/C.UTF-8/LC_MESSAGES/SYS_LC_MESSAGES
7fec9aff6000-7fec9aff7000 r--p 00000000 08:01 11302816           /usr/lib/locale/C.UTF-8/LC_PAPER
7fec9aff7000-7fec9aff8000 r--p 00000000 08:01 11302045           /usr/lib/locale/C.UTF-8/LC_NAME
7fec9aff8000-7fec9aff9000 r--p 00000000 08:01 11295311           /usr/lib/locale/C.UTF-8/LC_ADDRESS
7fec9aff9000-7fec9affa000 r--p 00000000 08:01 11302824           /usr/lib/locale/C.UTF-8/LC_TELEPHONE
7fec9affa000-7fec9affb000 r--p 00000000 08:01 11295316           /usr/lib/locale/C.UTF-8/LC_MEASUREMENT
7fec9affb000-7fec9b002000 r--s 00000000 08:01 11324488           /usr/lib/x86_64-linux-gnu/gconv/gconv-modules.cache
7fec9b002000-7fec9b003000 r--p 00000000 08:01 11295314           /usr/lib/locale/C.UTF-8/LC_IDENTIFICATION
7fec9b003000-7fec9b004000 r--p 00000000 08:01 1703945            /lib/x86_64-linux-gnu/ld-2.28.so
7fec9b004000-7fec9b022000 r-xp 00001000 08:01 1703945            /lib/x86_64-linux-gnu/ld-2.28.so
7fec9b022000-7fec9b02a000 r--p 0001f000 08:01 1703945            /lib/x86_64-linux-gnu/ld-2.28.so
7fec9b02a000-7fec9b02b000 r--p 00026000 08:01 1703945            /lib/x86_64-linux-gnu/ld-2.28.so
7fec9b02b000-7fec9b02c000 rw-p 00027000 08:01 1703945            /lib/x86_64-linux-gnu/ld-2.28.so
7fec9b02c000-7fec9b02d000 rw-p 00000000 00:00 0 
7ffc0365b000-7ffc0367c000 rw-p 00000000 00:00 0          [stack]
7ffc03686000-7ffc03689000 r--p 00000000 00:00 0          [vvar]
7ffc03689000-7ffc0368b000 r-xp 00000000 00:00 0          [vdso]

(I removed some spaces)

So even when running a program as simple as /bin/cat, the virtual address space inside the process is in practice much more complex than what your right picture suggests.

On Linux, shared libraries can be loaded (as plugins) at runtime with dlopen(3), and my manydl.c program shows that you can generate and load many hundred thousands of plugins in the same process.


An operating system with virtual memory will provide each process with its own address space, so the picture looks like the one on the right.  Given that, addresses and addressing are always used in context of a particular address space.  Addresses between processes may be seen as numerically overlapping, however, they represent different memory due to the separate address spaces.

Even without virtual memory (or with virtual memory but only one address space), broadly speaking, the operating system is more likely to give each process a single chunk of contiguous memory to carve up into text/data/bss/heap/stack rather than interleave sub sections of the processes, so the picture probably still looks like the one on the right; As there is only one address space to use, addresses in different processes would not overlap numerically.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.