skip to content

When you print the memory map of a running process, which regions does it contain and what does each hold?

level: juniorimportance: must knowfreq 76%

answer

  1. not one undifferentiated pool
  2. each range carries permissions
  3. some shared, some per thread
  4. code and constants are read-only
  5. one stack plus thread-local block per thread

basics

~20 s

A process maps several regions with different rules: read-only code and constants, initialized static data, zero-filled static data, one growable heap, one stack per thread, and per-thread thread-local storage. Placement decides lifetime and who may write.

solid answer

~40 s

A process maps several ranges, each with its own permissions and its own rules. There is the **code** region, readable and executable but not writable; a **read-only constants** region holding literal text and constant tables; **initialized static data** for process-lifetime variables that start non-zero, and a **zero-filled static data** region for those that start at zero; the **heap**, one per process, grown on demand and reclaimed either explicitly or by a collector; **one stack per thread**; and a small **thread-local storage** block per thread. Two questions separate them all: how many copies exist (one per process, or one per thread), and may the program write there. Placement, not the pointer's type, decides whether a store faults and how long the bytes survive.

go deeper

for a junior

Be able to name the regions and say what each holds: code, read-only constants, static data, the heap, one stack per thread, thread-local storage.

for a middle

Explain what actually differs between them - permissions, how many copies exist, and the moment each region's extent is decided and released.

for a senior

Use the map when diagnosing. Know which region a symptom implicates before reaching for a tool, and which regions grow with load or with thread count.

for a principal

Judge which regions a design leans on - many per-thread reservations against one shared heap - and set the footprint envelope processes in your fleet must fit.

## A process is a set of mappings, not one pool When a program starts, the loader does not hand it a single undifferentiated block of memory. It builds a **memory map**: a list of address ranges, each backed by something and each carrying **permissions** - readable, writable, executable. Almost everything else in this subject follows from that map, because which range an address falls in decides how long its bytes live, who is allowed to change them, and what happens when the program tries. A conventional map for a running multi-threaded daemon holds these regions. - **Code** - the machine instructions of the program and of every library it loaded. Mapped readable and executable, not writable. One mapped copy serves every thread. - **Read-only constants** - literal text, jump tables, constant lookup tables: values fixed at build time that the program promises never to change. Mapped without write permission, which is why a store through a pointer into it traps. - **Initialized static data** - variables that live for the whole process and start at a non-zero value. Their starting bytes ship inside the program image. - **Zero-initialized static data** - the same process lifetime, but a starting value of zero. The image records only the size, and the loader supplies a zero-filled range. - **The heap** - one region per process. It grows on demand when the allocator asks the operating system for more address space, and blocks inside it are reclaimed explicitly or by a collector, depending on the ecosystem. - **Per-thread stacks** - one region per thread, each holding that thread's chain of active calls. Created with the thread, released when it exits. - **Thread-local storage** - a small block per thread holding variables declared as one-per-thread. It shares the thread's lifetime, but unlike the stack beside it, its contents outlive every individual call. ## The two questions that separate them | Region | How many | Program may write | Extent decided | Ends when | |---|---|---|---|---| | Code | one, shared | no | build time | process exits | | Read-only constants | one, shared | no | build time | process exits | | Initialized static data | one, shared | yes | build time | process exits | | Zero-filled static data | one, shared | yes | build time (size only) | process exits | | Heap | one, shared | yes | run time, grows | block released | | Stack | one per thread | yes | thread creation | frame returns, thread exits | | Thread-local storage | one per thread | yes | build and run time | thread exits | Read that table column by column and the whole subject is in it: **how many copies exist** and **may the program write** are the two axes that actually distinguish these regions from one another. ## Why the split exists 1. **Protection.** Marking instructions and constants non-writable turns a whole class of bugs - a stray pointer walking past the end of a buffer into code - into an immediate, localised fault instead of silent corruption discovered hours later. 2. **Sharing.** Because code and constants are never written, many processes running the same program can be given the same underlying copy. A region that is written cannot be shared that way. 3. **Cost.** Reserving a range is cheap; shipping bytes is not. A region whose contents are known to be all zeros needs only a size recorded, which is why a large zeroed static array costs nothing in the program file. ## What this buys you in an interview The next question is almost always *which region does this value land in, and why*, and the map is what you answer it with: - A value whose lifetime is the whole process and whose name is fixed at build time goes to static data. - A value that belongs to one call, in one thread, goes to that thread's stack. - A value whose size or lifetime is not settled until run time goes to the heap, which is why it costs a pointer hop and a reclamation obligation. - A value that must be one-per-thread rather than one-per-process goes to thread-local storage - a distinct region, not a flavour of either of the others. Notice how much the map explains with no further machinery: why running 800 threads instead of 8 multiplies part of the footprint and leaves the rest untouched (only the per-thread regions are duplicated); why two identical literals can legitimately share one address (a region nobody writes can be de-duplicated safely); why you cannot hand a value to another thread by leaving it on your own stack (that range belongs to your call chain). ## Where this stops The map is a list of address ranges, not a statement about physical memory. How those ranges are backed by hardware - page tables, what is resident, what has been paged out - is a separate operating-system subject, and so is any one platform's naming for its own runtime areas. Learn the regions and their rules first; the backing story sits underneath them and answers a different question.

  • Which of these regions already exist before the program's first instruction runs?
    Code, read-only constants, both static-data regions and the first thread's stack are mapped by the loader before entry. The heap starts empty or tiny and grows on demand, and every further stack and thread-local block appears only when its thread is created.
  • Where does a large constant lookup table end up, and can the program change it?
    In the read-only constants region, if it is declared constant and fully initialized at build time: the bytes ship inside the program image and the mapping carries no write permission, so a store through a pointer into it traps. A table that must be mutated has to be copied into a writable region first.
  • Does a value's declared type decide its region?
    No. The region follows storage duration and who can still reach the value: process-lifetime variables go to static data, per-call values to the calling thread's stack, values whose size or lifetime is unknown at build time to the heap. The same type can land in any of them.

A workshop is not one table: there is a wall of printed instructions nobody may edit, a shelf of fixed reference cards, a shared parts bin everyone draws from, and one small private bench per worker.

saying these in an interview costs you the question

  • Says a process has only two regions, a stack and a heap
  • Thinks all threads share a single stack
  • Believes literal constants live on the heap
  • Claims every mapped region is writable by the program
  • Thinks static data is allocated fresh on each call