Stack, Heap and Data Segments

2
0

Introduction

A process address space is divided into memory regions because different program data has different roles and lifetimes. Program instructions, global variables, dynamic objects, and function-call data are not managed in the same way.

The main regions are code or text, data, BSS, heap, and stack. The deciding idea is simple: what the data is and how long it lives usually tells us where it belongs.

Process Memory Layout

A running program contains instructions to execute, global state, dynamically allocated objects, and function-call information. The operating system and runtime organize these into separate regions inside the process address space.

The common layout includes:

  • Code or text: Executable program instructions.

  • Data: Initialized global and static variables.

  • BSS: Uninitialized or zero-initialized global and static variables.

  • Heap: Dynamically allocated memory used during runtime.

  • Stack: Function-call frames, parameters, return addresses, and local variables.

This layout is a conceptual model. Exact placement can differ by operating system, executable format, architecture, compiler, and security settings.

What lives inside address space

What lives inside address space

Code, Data and BSS Segments

The code, data, and BSS segments separate program instructions from global or static state. These regions are usually created when the program is loaded.

Segment

Stores

Example

Code/Text

Executable instructions

Program machine code

Data

Initialized global/static variables

int counter = 10;

BSS

Zero-initialized or uninitialized global/static variables

static int visits;

The code segment is usually read-only and executable. The program should be able to run its instructions, but accidental writes to the instruction region should be blocked.

The data segment stores global or static variables that already have explicit initial values. The BSS segment stores static-duration variables that begin as zero or have no explicit nonzero value.

Heap Memory

The heap is the dynamic memory region. It is used when a program asks for memory while it is running, and that memory is not tied to a single function call.

Heap memory is used for:

  • Dynamic allocation: Memory requested through mechanisms such as malloc or new.

  • Longer lifetime: The memory can outlive the function that allocated it.

  • Shared process access: Threads in the same process can access heap memory because they share the process address space.

  • Runtime-sized objects: Structures whose size or lifetime is decided during execution.

The heap is managed by an allocator. Many allocation requests are handled by the runtime allocator first; the allocator asks the operating system for more memory only when it needs more space.

Heap and Stack Memory

Heap and Stack Memory

Stack Memory

The stack stores function-call data for a thread. Each active function call has a stack frame, and that frame contains information needed while the function is running.

The stack stores function-call information, including function-call frames, return addresses, parameters, local variables, and saved registers or other call-related information.

The stack is about call lifetime. A stack frame is created when a function call begins and is removed when that function returns.

If main calls solve, and solve calls helper, the stack contains frames for those active calls. When helper returns, its frame disappears, and local variables inside that frame are no longer valid.

Stack vs Heap

Stack and heap are often compared because both store program data, but they are used for different lifetimes and managed differently.

Point

Stack

Heap

Lifetime

Automatic, tied to function calls

Dynamic, controlled by program or runtime

Main use

Call frames and local variables

Runtime allocations and dynamic objects

Management

Created and removed with calls/returns

Allocated and freed explicitly or by runtime

Thread behavior

Each thread has its own stack

Threads in a process share the heap

Example: Function Call and Dynamic Allocation

Suppose a function declares a local variable:


void helper() {
    int x = 5;
}

The variable x belongs to the stack frame of helper. When helper returns, that frame is removed, so returning a pointer or reference to x would be unsafe.

Now consider dynamic allocation: p = malloc(100)

Here, the allocator finds or requests heap space and returns a pointer to the allocated block. That block remains allocated until the program releases it using free(p) or an equivalent runtime mechanism.

Common Bugs

The most common stack-related mistake is using local stack data after its function has returned. The local variable belonged to a stack frame that no longer exists.

Common heap bugs include:

  • Memory leak: Allocated memory is never released.

  • Use-after-free: Code uses memory after it has been freed.

  • Double free: The same allocation is freed more than once.

These bugs come from misunderstanding lifetime. Stack data disappears automatically with function returns, while heap data must be managed according to its allocation rules.

Summary

A process memory layout separates code, data, BSS, heap, and stack because each region has a different purpose. Code stores instructions, data stores initialized globals and statics, BSS stores zero-initialized or uninitialized statics, heap stores dynamic allocations, and stack stores function-call data.

The central rule is to connect memory region with lifetime. Stack memory follows function-call lifetime, while heap memory follows dynamic lifetime controlled by the program or runtime.

CS Core

Read Similar Blogs

Comments0