Free lesson · Operating Systems
Every running program is a process with a unique PID
A Program Is Not a Process
This is the first distinction that matters, and interviewers test it directly: a program and a process are not the same thing.
A program is a file sitting on your hard drive. It is a set of instructions written in some programming language, compiled into machine code (or kept as source code for interpreted languages), and stored on disk. Right now, your computer has hundreds of programs on it - a web browser, a text editor, a music player, Python, Java, dozens of system utilities. They are just files. They are not doing anything.
A process is what happens when you run that program. When you double-click your web browser, the operating system reads the browser's program file from disk, loads it into memory, sets up everything the program needs to run, and starts executing its instructions. That running instance is a process.
Here is why this distinction matters: you can have multiple processes running the same program. Open three terminal windows and run the same Python script in each one. You now have three processes, all running the same program. Each process has its own separate memory, its own state, its own data. If one crashes, the other two keep running. They are independent instances of the same instructions.
graph LR
subgraph DISK["On Disk (Programs)"]
P1["chrome.exe<br/>(program file)"]
P2["python3<br/>(program file)"]
end
subgraph RAM["In Memory (Processes)"]
PR1["Chrome Tab 1<br/>PID: 1234"]
PR2["Chrome Tab 2<br/>PID: 1235"]
PR3["Chrome Tab 3<br/>PID: 1236"]
PR4["Python Script A<br/>PID: 2001"]
PR5["Python Script B<br/>PID: 2002"]
end
P1 --> PR1
P1 --> PR2
P1 --> PR3
P2 --> PR4
P2 --> PR5
This diagram shows the relationship between programs and processes. On the left side, two program files sit on disk: chrome.exe and python3. On the right side, five processes are running in memory. Three Chrome processes (with different PIDs) were all created from the same chrome.exe program. Two Python processes were created from the same python3 program. One program can create many independent processes.
Interview: This is a direct interview question. When an interviewer asks "what is the difference between a program and a process?", they want to hear:
"A program is a passive entity - a file containing instructions stored on disk. A process is an active entity - a running instance of a program with its own memory space, program counter, registers, and system resources. Multiple processes can be created from the same program, and each runs independently."
The key word is instance. A process is an instance of a program, just like an object is an instance of a class in object-oriented programming. If the interviewer is a senior engineer, they will appreciate that analogy.
What the OS Tracks for Every Process
When the OS creates a process, it does not just load the program's code into memory and start running it. It also creates a data structure that tracks everything about that process - its current state, what resources it is using, where it is in its execution, and more.
Think of it like a patient file at a hospital. The patient (the process) is the living, active entity. But the hospital also keeps a detailed file about each patient - their name, their room number, their medical history, what medications they are on, which doctor is assigned to them. If a doctor needs to switch from treating one patient to another, they can look at the file to pick up exactly where the previous doctor left off.
The OS keeps a similar file for each process. It is called the Process Control Block (PCB), and we will cover it in detail in Topic 4 of this module. For now, here is what the OS needs to track:
The process ID (PID). Every process gets a unique number. This is how the OS tells processes apart. When you run ps or top in a Linux terminal, the numbers you see are PIDs. When you kill a process with kill 1234, you are referring to it by PID.
The process state. Is this process currently running on the CPU? Is it waiting for something (like data from the disk)? Is it ready to run but waiting for the CPU to be available? The OS tracks which state every process is in so it knows what to do with it. We cover process states in detail in Topic 3.
The program counter. This is the address of the next instruction the process should execute. When the OS pauses a process (to let another process run), it saves the program counter so it can resume the paused process later at exactly the right place.
CPU registers. The CPU has a set of small, fast storage locations called registers that hold the data the process is actively working with. When the OS switches from one process to another, it saves the current process's register values and loads the next process's register values. This save-and-restore is part of what makes a context switch work.
Memory information. Where in RAM is this process's code? Where is its data? Where is its stack? Where is its heap? How much memory has it been allocated? The OS tracks all of this so it can manage memory efficiently and make sure processes do not interfere with each other's memory.
I/O status. Which files does this process have open? Which network sockets is it using? What I/O operations is it waiting for? The OS tracks these so it can clean up properly when the process finishes and so it can resume the process when the I/O it was waiting for completes.
Scheduling information. How much CPU time has this process used? What is its priority? When was it last scheduled? The OS uses this information to decide which process should run next. We cover scheduling algorithms in Module 03.
The Anatomy of a Process in Memory
When the OS loads a process into memory, the process's memory is organized into distinct regions. Understanding this layout matters for interviews because it comes up in questions about stack overflows, memory leaks, and how programs use memory.
graph TD
subgraph MEMORY["Process Memory Layout (Low to High Address)"]
TEXT["Text Segment<br/>────────────<br/>The compiled machine code<br/>of your program.<br/>Read-only. Shared across<br/>processes running the<br/>same program."]
DATA["Data Segment<br/>────────────<br/>Global and static variables<br/>that were initialized<br/>when the program started."]
BSS["BSS Segment<br/>────────────<br/>Global and static variables<br/>that were NOT initialized.<br/>Filled with zeros by the OS."]
HEAP["Heap ↓<br/>────────────<br/>Dynamic memory allocation.<br/>Grows downward toward<br/>higher addresses.<br/>malloc() / new allocate here."]
FREE["... Free Space ..."]
STACK["↑ Stack<br/>────────────<br/>Function call frames.<br/>Local variables, return<br/>addresses, function arguments.<br/>Grows upward toward<br/>lower addresses."]
end
TEXT --> DATA --> BSS --> HEAP --> FREE --> STACK
This diagram shows the memory layout of a process from low addresses at the top to high addresses at the bottom. The text segment at the bottom holds the program's compiled code and is read-only. Above it is the data segment with initialized global variables, then the BSS segment with uninitialized global variables. The heap grows downward from there, used for dynamic memory allocation. The stack grows upward from the top of the address space, used for function calls and local variables. Free space sits between the heap and the stack.
Let us walk through each region.
The Text Segment (Code)
This is where your program's actual compiled instructions live. When you write a Python function or a Java method, the compiled version of those instructions ends up here. The text segment is read-only - the process can execute these instructions but cannot modify them. This is a protection mechanism: a bug in your code should not be able to rewrite the code itself.
An interesting detail: if you run three instances of the same program, the OS can share a single copy of the text segment across all three processes. The code is identical and read-only, so there is no reason to duplicate it. This saves memory.
The Data Segment
This holds global and static variables that were given initial values when the program was written. For example, if your C program has int counter = 42; as a global variable, that 42 lives in the data segment. Unlike the text segment, the data segment is read-write - your program can change these values during execution.
The BSS Segment
BSS stands for "Block Started by Symbol" - a historical name that nobody remembers the origin of. This holds global and static variables that were not initialized in the source code. For example, int counter; without an initial value. The OS fills this entire segment with zeros when the process starts. It is separated from the data segment because the OS does not need to store the initial values on disk (they are all zero), which saves space in the program file.
The Heap
The heap is where dynamic memory allocation happens. When your program calls malloc() in C, new in Java, or creates objects in Python, the memory comes from the heap. The heap grows as your program allocates more memory and shrinks (if the program properly frees memory).
Memory leaks happen when your program allocates memory on the heap but never frees it. Over time, the heap grows and grows until the process runs out of memory. This is why memory management matters - and it is a common topic in interviews.
The Stack
The stack is where function calls are managed. Every time your program calls a function, a new stack frame is pushed onto the stack. The stack frame contains the function's local variables, its arguments, the return address (where to go back to when the function finishes), and saved register values.
When the function returns, its stack frame is popped off the stack. This is why local variables disappear when a function returns - the memory they occupied on the stack is reclaimed.
The stack has a fixed maximum size (typically 1–8 MB depending on the OS and configuration). If your program uses too much stack space - usually because of deep or infinite recursion - it runs out of stack and crashes with a stack overflow. This is where the name of the popular programming Q&A website comes from.
The Critical Interview Detail: Heap vs Stack
The heap-versus-stack distinction is one of the most commonly asked memory questions in interviews. Here is the comparison interviewers expect you to know:
| Property | Stack | Heap |
|---|---|---|
| What goes here | Local variables, function arguments, return addresses | Dynamically allocated objects (malloc, new) |
| How it grows | Automatically, as functions are called and return | Manually, as the programmer allocates and frees memory |
| Speed | Very fast - just move the stack pointer | Slower - requires finding a free block of the right size |
| Size | Small and fixed (1–8 MB typically) | Large and flexible (limited by available memory) |
| Lifetime | Automatic - freed when the function returns | Manual - programmer must free it (or garbage collector) |
| Risk | Stack overflow from deep recursion | Memory leaks from forgetting to free |
Tip: In an interview, explain the tradeoff concisely: "Stack allocation is fast but limited in size and lifetime - it is automatic and dies when the function returns. Heap allocation is slower but flexible - it persists until explicitly freed or garbage collected. Use the stack for small, short-lived data. Use the heap for large or long-lived data."
Seeing a Process in Action
Let us make this concrete. On a Linux or macOS system, you can see your processes right now. Open a terminal and run:
ps aux | head -20
This shows you a list of running processes. Each line is one process. The columns include the user who owns the process, the PID, CPU and memory usage, the start time, and the command that started the process.
You can also see the memory layout of a specific process. On Linux, every process has a directory under /proc that exposes its internals. If a process has PID 1234, you can see its memory map:
cat /proc/1234/maps
This shows each memory region - the text segment, data segment, heap, stack, shared libraries, and more - along with the virtual address range and permissions (read, write, execute) for each region. We will explore /proc in depth in Module 14 (Linux Internals), but it is useful to know it exists now.
You can also create a process yourself and see what happens:
import os
# Every running program is a process with a unique PID
print(f"I am a process!")
print(f"My Process ID (PID): {os.getpid()}")
print(f"My Parent's PID: {os.getppid()}")
When you run this script, Python creates a process, the OS assigns it a PID, and the script prints that PID. The parent PID (getppid()) is the PID of the process that started this one - typically your terminal shell.
What Makes a Process Different from Just "Running Code"
The key insight - and the thing that separates a superficial answer from a strong interview answer - is that a process is more than running code. A process is a resource container. It is the entity to which the OS assigns resources: memory, CPU time, open files, network sockets, environment variables, a current working directory, signal handlers, and more.
When you say "I have a process," you are saying "I have an isolated execution environment with its own address space, its own set of resources, and its own lifecycle, managed by the operating system."
This isolation is the critical property. Process A cannot read Process B's memory. Process A's crash does not affect Process B. Process A's open files are separate from Process B's open files. The OS enforces these boundaries. This is why servers run different services in separate processes - if the email service crashes, it should not take down the web server.
Threads, which we cover in Module 02, share many of these resources within a single process. That sharing is what makes threads lighter-weight but also what makes them more dangerous. Understanding the process model first - with its strong isolation - makes the thread model easier to understand by contrast.
Interview: A strong definition of a process for interviews:
"A process is an instance of a running program, managed by the operating system as an independent unit of resource allocation and protection. Each process has its own virtual address space, its own set of open file descriptors, its own registers and program counter, and its own entry in the OS's process table. The OS isolates processes from each other so that one process's failure cannot corrupt another process's state."
This definition covers four things interviewers care about: it distinguishes process from program, it mentions isolation, it mentions the resources a process owns, and it mentions that the OS manages the lifecycle.
Why Every Concept in This Module Matters
This topic gave you the foundation: what a process is, how its memory is laid out, and why processes matter. The remaining topics in this module build on this foundation in a specific order:
Topic 2 explains how processes are created - the fork() and exec() system calls that bring new processes into existence. Topic 3 covers the states a process moves through during its lifetime - from new to ready to running to waiting to terminated. Topic 4 details the Process Control Block - the data structure the OS uses to track everything about a process. Topic 5 puts it all together into the complete lifecycle - birth, execution, death, and what can go wrong (zombie and orphan processes). Topic 6 introduces system calls - the mechanism programs use to ask the OS for services. Topic 7 explains the user mode / kernel mode boundary - the protection mechanism that keeps user programs from accessing hardware directly. Topic 8 collects the most common interview questions about processes and shows you how to structure your answers.
Each topic depends on the ones before it. If you understand what a process is (this topic), you are ready to understand how one is created.
Exercise: Starter: Open a terminal on your computer and run
ps aux | wc -lto count how many processes are currently running. The number will probably surprise you - a typical desktop system has 200–400 processes running at any time, even when you feel like "nothing is happening." Each one has its own memory layout, its own PID, and its own PCB in the kernel.Intermediate: Write a small program in any language that prints its own PID and then sleeps for 30 seconds. While it is sleeping, open another terminal and find it in the process list using
ps aux | grep [your-program-name]. Can you see the PID, memory usage, and CPU time? Try running two instances of the same program at the same time - confirm that they have different PIDs.Advanced: On a Linux system, run a simple program (like
sleep 60) and then inspect its memory map usingcat /proc/[PID]/maps. Can you identify the text segment, data segment, heap, stack, and shared libraries? Which segments are marked read-only? Which are read-write? Which are executable?