Linux organizes the virtual memory space of a process into segments, each serving a specific purpose. This is crucial for memory safety, performance, and debugging.
Here’s a standard layout from low to high memory:
+-------------------------+ | Text Segment | ← Executable instructions +-------------------------+ | Initialized Data (.data)| ← Global/static vars with initial values +-------------------------+ | BSS Segment | ← Zero-initialized global/static vars +-------------------------+ | Heap | ← Grows upward; dynamic memory +-------------------------+ | Memory Mappings | ← Shared libs, files, mmaps +-------------------------+ | Stack | ← Grows downward; one per thread +-------------------------+
Each of these has a well-defined purpose and can be observed and debugged.
Segment Breakdown
Text Segment (.text)
Contains executable machine code. Read-only to prevent modification at runtime (helps security via W^X policy). Any attempt to write here causes a segmentation fault.
void greet() {
std::cout << "Hello\n"; // code for this function goes in .text
}
Data Segment (.data)
Stores initialized global and static variables.
int count = 5; // Goes in data segment
BSS Segment (.bss)
Stores uninitialized or zero-initialized global/static variables.
static int flag; // Goes in BSS (initialized to 0 by default)
Heap
Dynamically allocated memory at runtime. Grows upward as memory is allocated. Managed manually (malloc/free, new/delete). Prone to memory leaks and fragmentation if misused.
int* arr = new int[10]; // Allocated on heap
Memory-Mapped Region
Shared libraries (e.g., libc.so, libbinder.so), file mappings, mmap() regions. Includes code from .so files, which Android uses extensively in native services.
void* addr = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
Stack
Used for function call frames, local variables, return addresses. Each thread has its own stack. Grows downward, from higher to lower addresses. Exceeding stack size leads to stack overflow.
void foo() {
int x = 42; // Stored on stack
}
View Process Memory in Practice (Linux/Android)
You can inspect a running process’s memory layout using:
/proc/<pid>/maps
This file shows all memory segments for a process.
cat /proc/1234/maps
Typical output:
00400000-0040c000 r-xp 00000000 08:01 123456 /usr/bin/myapp
0060c000-0060d000 r--p 0000c000 08:01 123456 /usr/bin/myapp
0060d000-0060e000 rw-p 0000d000 08:01 123456 /usr/bin/myapp
7fff5b1f9000-7fff5b21a000 rw-p 00000000 00:00 0 [stack]
Use this to:
- Locate text, data, stack, heap
- See which .so libraries are mapped
- Debug memory leaks, crashes, or access violations
Other Process Resources to Know
| Resource | Where to Find / How to Inspect |
|---|---|
| File Descriptors | /proc/<pid>/fd/ — shows symbolic links to open files |
| Environment Vars | /proc/<pid>/environ |
| Command Line Args | /proc/<pid>/cmdline |
| CWD | /proc/<pid>/cwd |
| Memory Maps | /proc/<pid>/maps |
| Threads | /proc/<pid>/task/ — each thread gets a directory |
Leave a comment