Where we are: from "alive" to "what it is made of"
In the previous guide we drew the great line between a program and a process: the program is the cookbook on the shelf, the process is the recipe actually being cooked. We said a process carries the in-progress state that running requires, but we left that state as a vague bundle. This guide pries the lid off. By the end you will be able to point to where a variable lives, why a giant array can make a tiny file, and how the kernel can freeze a process mid-step and thaw it later as if nothing happened.
A process really has two halves to understand. One half is what the process can see: its own private memory, called the address space, laid out into recognizable neighborhoods. The other half is what only the kernel can see: a hidden record about the process, the process control block, kept safely outside the process's reach. We will walk the visible half first, then the hidden half, and finish by watching them work together.
The four neighborhoods of the address space
Picture the address space as a private apartment numbered room by room, from the front door at address 0 up to the far wall at the highest address. The process can arrange furniture however it likes inside, and it cannot peek into anyone else's apartment. Four well-known regions live in this apartment, and once you can name them, most memory mysteries dissolve. Reading from the low addresses upward: the text segment, then the data and BSS, then the heap, and far up top the stack.
The text segment holds the program's machine instructions — the compiled code the CPU executes. It is the printed recipe steps: you read them, you never scribble over them, so the kernel marks these pages read-only and executable. Because the instructions are identical for every instance and never change, the kernel can keep one physical copy and share it among all processes running the same program. Just above it sits the data segment for global and static variables that start with a non-zero value baked into the program (like a counter set to 1), and the BSS for global and static variables that start at zero. The clever part: zero-start variables need no stored values, only a reserved size, which is exactly why a program declaring a million-byte zero-filled array still compiles to a tiny executable.
The top two neighborhoods are the lively ones. The heap is a communal supply room: when the program asks for memory at run time (a malloc in C, a new object in a higher-level language), the heap manager hands back a block, and the program returns it when done. The heap grows upward as more is requested. The stack is a pile of cafeteria trays: each function call pushes a frame holding that call's local variables, parameters, and return address, and each return pops its frame off. The stack sits at the high end and grows downward, so the heap (growing up) and the stack (growing down) advance toward each other across the big empty gap in the middle, each leaving room for the other to expand.
A subtle truth: the addresses are virtual
Here is the quiet trick that makes the private-apartment image honest. The numbers a process uses are logical (virtual) addresses, not real locations in RAM. The same address number in two different processes refers to two different physical cells, because the hardware translates each process's addresses separately, on the fly. So two processes can both happily use "address 4096" with no conflict at all. This is why the apartments stay private and why each process can pretend it owns a clean block of memory starting at zero.
A direct consequence trips up many beginners: the size of the address space is not the amount of RAM in use. A 32-bit process can name every address from 0 to 2^32 - 1, a 4 GB range, even on a machine holding only 1 GB of RAM. Almost all of that range is empty. Only the pages the process actually touches — some code, some data, the heap and stack pages it has reached — are backed by real memory. The address space is a map of possible addresses, not a measure of memory consumed. We will meet the machinery that does this translation (the MMU and page tables) when we climb the memory-management rungs; for now, just hold the idea that what a process sees is a private, virtual view.
The PCB: the kernel's chart for one process
Everything above is what the process can see. Now meet what only the kernel sees. Think of a hospital keeping one chart per patient: name and ID, current condition, medications, pending tests. A nurse can set a patient aside and pick them up later because everything needed to resume care is on the chart. The process control block, or PCB, is exactly that chart for one process — the kernel's private record of everything it needs to pause this process and resume it correctly.
What goes on the chart? A useful test answers it: anything the kernel must remember about the process during the times it is not running has to live in the PCB, because the moment another process runs, the CPU's registers are overwritten. So a typical PCB holds the process identifier (PID); the current state (running, ready, waiting); the saved CPU registers, crucially including the program counter that says which instruction comes next; memory-management information saying where this process's address space lives; the list of open files; scheduling information like priority; and accounting data such as CPU time used. The PCB is, in a very real sense, the process condensed into a single record the kernel can hold in its hand.
Putting it together: pausing and resuming a process
The address space and the PCB are not two separate facts; they are two halves of one mechanism. With many processes sharing one CPU, the kernel must constantly stop one and start another. The PCB is precisely what makes that possible without the running program ever noticing the interruption. Here is the heart of it, the save-and-restore that the next guide will study in full as the context switch.
- A reason to switch arrives: the running process's turn ends, an interrupt fires, or it asks for something not yet ready and must block.
- The kernel copies the running process's CPU registers and program counter out of the CPU and into that process's PCB, freezing it mid-stride.
- The kernel chooses the next process to run and updates the memory-management state (the pointer to whose address space is active) so the hardware will now translate the new process's virtual addresses.
- The kernel copies the chosen process's saved registers and program counter from its PCB back into the CPU, and execution resumes at exactly the instruction it had reached — as if it never stopped.
Now you can see why both halves matter together. Switching the address-space pointer is what makes "address 4096" mean the new process's memory instead of the old one's. Restoring the registers from the PCB is what lets the program counter land back on the exact next instruction. The kernel does not store any of this in the process's own memory — that memory belongs to the process and might even be paged out to disk. It stores the resumable snapshot in the PCB, and it keeps the PCBs of every process it knows about in one master list, the process table, so it can find, schedule, and clean up any process by walking that table.