Why Does Your C++ Program’s Memory Look Like This? From Punch Cards to Virtual Memory
This article traces the evolution of memory layout from early punched‑card computers through assembly‑level innovations, segment‑based designs, and virtual memory, then demonstrates a real 32‑bit Linux C++ program showing where globals, stack, heap, and mapped regions reside, and explains how this knowledge helps debug segmentation faults, stack overflows, and memory leaks.
Introduction
Understanding where variables reside (e.g., int number = 42;) explains the difference between global and local storage, and why segmentation faults occur.
Early computers – the birth of memory management
From punched cards
In the 1940s‑50s programs were sequences of holes on paper tape. Memory was a few kilobytes, only one program ran at a time, and there was no operating system, so there was no concept of a structured memory layout.
Memory was extremely scarce
Only one program executed at a time
Programs directly controlled the hardware
Assembly‑era innovations
Late 1950s introduced symbolic names (e.g., STORE RESULT) and a simple three‑region model:
┌───────────────┐
│ Stack │
├───────────────┤
│ Data │
├───────────────┤
│ Program Code│
└───────────────┘Problems remained: safety hazards, wasted space, and difficulty extending memory.
Segmentation
From conceptual separation to physical isolation
1960s hardware (e.g., IBM System/360, DEC PDP) added memory protection, allowing distinct permission regions.
Segmentation matures
By the late 1970s (Unix V7) memory was divided into functional zones:
┌───────────────┐
│ Stack │ ← function calls, locals (grows down)
├───────────────┤
│ Memory‑Mapped│ ← shared libraries, files
├───────────────┤
│ Heap │ ← dynamic allocation (grows up)
├───────────────┤
│ BSS │ ← uninitialized globals
├───────────────┤
│ Data Segment│ ← initialized globals
├───────────────┤
│ Code Segment│ ← program instructions
└───────────────┘The BSS story
BSS (“Block Started by Symbol”) originated as a pseudo‑instruction on IBM 704/709 to reserve space for uninitialized data. Unix inherited it, saving disk space because zero‑filled data is created at load time.
Benefits of segmentation
Code protection : read‑only code segment prevents accidental overwrites.
Resource saving : BSS occupies no space in the executable.
Functional separation : different data types are stored separately, easing management.
Virtual memory – the modern era
From physical limits to virtual freedom
Late 1970s introduced virtual memory, giving the illusion of abundant address space while mapping pages to physical RAM or disk.
Memory‑mapping: sharing and interaction
BSD Unix (early 1980s) used memory‑mapping for shared libraries, large file access, and fast inter‑process communication.
Classic 32‑bit Linux layout
High address (0xFFFFFFFF) ── Kernel space
│ Stack (grows down)
│ ↓
│ ── Memory‑mapped region
│ ↑
│ Heap (grows up)
│ BSS (uninitialized globals)
│ Data segment (initialized globals)
Low address (0x00000000) ── Code segmentThe 4 GB address space is split: user space 0‑3 GB, kernel space 3‑4 GB.
Why does the stack grow down?
Historical inheritance from early CPUs (e.g., Intel 8086).
Memory utilization: stack down, heap up maximizes free middle space.
Register design: some instruction sets make downward growth more efficient.
Real‑world C++ memory layout on 32‑bit Linux
Sample code – revealing addresses
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <string.h>
// Global – data segment
int globalInitialized = 100;
// Global – BSS segment
int globalUninitialized;
const char* constString = "Hello World"; // read‑only data segment
void printAddresses() {
int localVar = 42; // stack
static int staticLocalVar = 999; // data segment
int* heapVar = (int*)malloc(sizeof(int));
*heapVar = 123;
void* mappedMemory = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
strcpy((char*)mappedMemory, "这是内存映射区");
printf("Code (function): %p
", (void*)printAddresses);
printf("Code (string): %p
", (void*)constString);
printf("Data (init global): %p
", (void*)&globalInitialized);
printf("BSS (uninit global): %p
", (void*)&globalUninitialized);
printf("Heap: %p
", (void*)heapVar);
printf("Mapped: %p
", mappedMemory);
printf("Stack (local): %p
", (void*)&localVar);
printf("Data (static local): %p
", (void*)&staticLocalVar);
free(heapVar);
munmap(mappedMemory, 4096);
}
int main() {
printAddresses();
return 0;
}Typical output (addresses vary):
Code (function): 0x5626c78681e9
Code (string): 0x5626c7869008
Data (init global): 0x5626c786b010
BSS (uninit global): 0x5626c786b024
Heap: 0x5626de6dd2a0
Mapped: 0x7f4d8f70c000
Stack (local): 0x7ffec9b4b8a4
Data (static local): 0x5626c786b014BSS optimization value
Placing large uninitialized arrays in BSS saves disk space because the executable records only the required size; the loader zero‑fills the memory at runtime.
Applying memory‑layout knowledge
Debugging segmentation faults
int main(){
int* p = NULL;
*p = 100; // segfault – writing to address 0
return 0;
}Knowing the address space helps locate the offending region.
Understanding stack overflows
void recursive(){
int bigArray[1000000]; // consumes stack
recursive();
}Excessive recursion or large stack allocations exceed the limited stack size (typically a few megabytes).
Preventing memory leaks
void potentialLeak(){
int* p = new int[1000];
// missing delete[] p leads to leak
}Awareness that heap memory must be freed avoids leaks.
Conclusion
The evolution from punched‑card programs to virtual memory shows how each advancement solved real problems—efficiency, safety, and simplicity—while preserving useful ideas like BSS. When you write int x = 10;, remember the centuries of engineering that decide where that value lives in memory.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
