Process Memory Layout

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

ResourceWhere 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

It’s Jdecoder

I am trying to decode the concepts into simple words and documenting items i know or currently learning.

Let’s connect

Design a site like this with WordPress.com
Get started