Linux Processes: Programs, Memory, and Execution
A brief guide to Processes.
Linux Processes: Programs, Memory, and Execution
A process is a running instance of a program. Understanding processes requires knowing how programs are loaded into memory, how their address spaces are organized, and how they receive arguments and environment variables.
1. Program vs. Process
A program is a passive file stored on disk. It contains machine instructions and possibly initialized data.
A process is an active execution instance of that program. It includes:
- Virtual address space
- CPU register state
- Stack and heap
- Open file descriptors
- Environment variables
- Process ID (PID)
- User and group credentials
1
2
3
4
5
Program on disk
|
| loaded by the kernel
v
Running process
Multiple processes can execute the same program simultaneously, each with its own execution state and virtual address space.
2. Process IDs
Every process has a unique process identifier called a PID.
Important identifiers include:
- PID: ID of the current process
- PPID: ID of its parent process
The parent process is the process that created the current process.
1
2
3
4
5
init/systemd
|
+── shell
|
+── command
A process can obtain its identifiers using functions such as:
1
2
getpid();
getppid();
3. Process Virtual Address Space
Each process normally has its own virtual address space. The same virtual address in two different processes may refer to different physical memory.
A simplified process memory layout is:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
High addresses
┌─────────────────────┐
│ Stack │
│ ↓ │
├─────────────────────┤
│ Memory mappings │
│ Shared libraries │
├─────────────────────┤
│ ↑ │
│ Heap │
├─────────────────────┤
│ BSS │
│ Initialized data │
│ Read-only data │
│ Text / code │
└─────────────────────┘
Low addresses
Text
Contains executable machine instructions.
Read-only data
Contains data such as string literals and constant values.
Initialized data
Contains initialized global and static variables.
BSS
Contains uninitialized or zero-initialized global and static variables.
The executable stores the required BSS size rather than storing large blocks of zero bytes. Therefore, a large global array may consume significant runtime memory without significantly increasing executable size.
Heap
Used for dynamically allocated memory, such as memory obtained through malloc().
Stack
Used for function calls, local variables, arguments, and saved execution state.
4. Stack Frames
When a function is called, the process typically creates a stack frame for that invocation.
A stack frame may contain:
- Local variables
- Function arguments
- Saved registers
- Return information
For example:
1
2
3
4
5
main()
|
+── function_a()
|
+── function_b()
The stack contains frames for the currently active calls:
1
2
3
4
5
6
7
┌─────────────────────┐
│ function_b frame │
├─────────────────────┤
│ function_a frame │
├─────────────────────┤
│ main frame │
└─────────────────────┘
When a function returns, its stack frame is removed.
This model explains:
- Local variable lifetime
- Recursion
- Stack overflow
- Function-call debugging
- Stack traces
5. Virtual Memory
Virtual memory provides each process with an isolated address space.
1
2
3
4
5
6
Process A Process B
Virtual address Virtual address
0x400000 0x400000
| |
v v
Different memory mappings
The operating system and CPU’s memory-management unit translate virtual addresses into physical addresses.
Virtual memory provides:
- Process isolation
- Memory protection
- Convenient address spaces
- Demand paging
- Shared libraries
- Memory-mapped files
A process usually cannot directly access another process’s memory without explicit operating-system support.
6. Command-Line Arguments
When a program is executed from a shell, it can receive command-line arguments.
For a command such as:
1
./program input.txt 100
the program receives:
argc: number of argumentsargv: array of argument strings
Conceptually:
1
2
3
4
5
6
argc = 3
argv[0] → "./program"
argv[1] → "input.txt"
argv[2] → "100"
argv[3] → NULL
The first argument, argv[0], usually contains the program name or invocation path.
Command-line arguments allow programs to receive configuration and input without interactive prompts.
7. Environment Variables
A process also receives an environment, which is a collection of key-value strings.
Examples include:
1
2
3
PATH=/usr/bin:/bin
HOME=/home/user
LANG=en_US.UTF-8
Programs can access environment variables through functions such as:
1
getenv("PATH");
The environment is inherited by child processes by default.
1
2
3
4
5
Parent process
|
| inherits environment
v
Child process
Environment variables are commonly used for:
- Executable search paths
- User configuration
- Locale settings
- Runtime configuration
- Credentials or service settings
Summary
The most important ideas are:
- A program is a file; a process is a running instance.
- Each process has a PID and a parent process ID.
- A process has its own virtual address space.
- Its memory is divided into areas such as text, data, BSS, heap, and stack.
- Function calls create stack frames.
- Virtual memory provides isolation and protection.
- Command-line arguments are passed through
argcandargv. - Environment variables provide inherited runtime configuration.
A useful mental model is:
1
2
3
4
5
6
7
8
9
10
11
12
13
Process
├── PID / PPID
├── Virtual address space
│ ├── Text
│ ├── Read-only data
│ ├── Data
│ ├── BSS
│ ├── Heap
│ └── Stack
├── CPU execution state
├── File descriptors
├── Command-line arguments
└── Environment