QUESTION
Does a visible virtual-address range mean physical memory has already been allocated?
A VMA describes protection and backing rules for a contiguous virtual-address range. Creating a VMA with mmap or exec does not immediately prepare every PTE and physical page. On access, a page fault connects a file page, zero page, or anonymous page.
/proc/PID/maps shows ranges and permissions, while smaps reports RSS/PSS and private/shared accounting. The single label 'heap' cannot explain malloc objects, the brk VMA, and allocator mmap arenas all at once.
STRUCTURE
Structure diagram
A visible VMA in maps does not mean every physical page is resident. A private page appears in an anonymous range on the first write fault.
CALL PATH
Call path
Address reservation, VMA registration, PTE installation, physical-page allocation, and RSS accounting happen at different times.
This diagram is not for memorizing function names. Follow which return value, file descriptor, memory mapping, or wait queue is passed to the next stage.
SOURCE COORDINATES
Linux 6.18.37 LTS source locations
Go beyond the glibc function to the files where the syscall implementation meets kernel objects. Each link points to the original file at the same tag.
| File | Function / structure | What to inspect |
|---|---|---|
| mm/mmap.c | do_mmap(), mmap_region() | Choose a VMA range and register it in the maple tree |
| mm/memory.c | handle_mm_fault(), do_anonymous_page() | Prepare a PTE and anonymous page on access |
| fs/proc/task_mmu.c | show_map_vma(), show_smap() | Inspect which fields /proc maps/smaps print |
COMPLETE PROGRAM
Complete runnable example
The code below is not pseudocode with explanatory lines omitted. It is a minimal example that can be built and run as a file.
cc -std=c17 -Wall -Wextra -O2 address_space.c -o address_space01#define _DEFAULT_SOURCE
02#include <stdio.h>
03#include <stdlib.h>
04#include <sys/mman.h>
05#include <unistd.h>
06
07int main(void)
08{
09 long page = sysconf(_SC_PAGESIZE);
10 size_t length = 256UL * 1024 * 1024;
11 unsigned char *area = mmap(NULL, length, PROT_READ | PROT_WRITE,
12 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
13 if (area == MAP_FAILED)
14 return 1;
15
16 printf("pid=%ld area=%p length=%zu page=%ld\n",
17 (long)getpid(), (void *)area, length, page);
18 puts("mapping created; press Enter");
19 getchar();
20 for (size_t offset = 0; offset < length; offset += (size_t)page)
21 area[offset] = 1;
22 puts("pages touched; press Enter");
23 getchar();
24 return munmap(area, length) != 0;
25}
CODE NOTES
Code notes
sysconf(_SC_PAGESIZE)Reads the page size from the execution environment instead of fixing it at 4096. Huge pages and base pages must be distinguished separately.
256UL * 1024 * 1024Reserves a large virtual range, but RSS need not grow by the same amount immediately after mmap returns.
MAP_PRIVATE | MAP_ANONYMOUSCreates a private VMA without file backing. An initial read may use the shared zero page, while a write can create a private anonymous page.
area[offset] = 1Writes to each base page, inducing minor faults and physical-page allocation.
munmap(area, length)Removes the VMA range and releases page-table entries and references. Truncated VMAs may be split or merged.
DETAILS
Detailed behavior
ASLR and PIE change addresses
The PIE main executable, shared objects, stack, and mmap base can change on every exec. Interpreting a runtime address requires combining the symbol offset with the mapping load bias.
A design that stores an absolute pointer in a log and reuses it in the next execution is invalid.
RSS and PSS answer different questions
RSS counts pages resident in a process's page tables and includes a shared page in every process. PSS divides the cost of a shared page by its mapping count to estimate proportional usage per process.
When examining allocator fragmentation, consider virtual size, RSS, and anonymous private dirty memory together.
Major and minor faults are not errors
A minor fault is a normal demand-paging event that can populate a page table without disk I/O. A major fault means the task had to wait for backing data from storage.
A latency-sensitive path may touch pages in advance or consider an mlock policy, trading memory pressure and startup cost for predictability.
OBJECTS
Objects and lifetimes
| Object | Creation and release | Values to inspect |
|---|---|---|
vm_area_struct | Created by mmap/exec/brk and removed by munmap/exec/exit | vm_start/end, vm_flags, vm_file |
PTE | Installed by fault or prefault and removed by reclaim/unmap | present, writable, dirty, accessed |
physical page/folio | Obtained by fault/read-ahead and reclaimable after mapping/references disappear | mapcount, refcount, dirty |
FAILURE PATH
Failure conditions and common misconceptions
| Observed symptom | Likely causes | How to verify |
|---|---|---|
| VIRT is large but RSS is small | The range was only reserved and its pages were not accessed | Compare maps with Rss in smaps |
| The first access has latency | A demand fault or file I/O | perf faults, mincore, major faults |
| mmap ENOMEM | VA range, map count, commit limit | vm.max_map_count, overcommit, address layout |
LAB
Verify it yourself
- Compare Rss and Private_Dirty in /proc/PID/smaps_rollup before and after the first Enter.
- Compare zero-page and private-page accounting between a read-only loop and a write loop.
- Apply madvise(MADV_HUGEPAGE/NOHUGEPAGE) and compare AnonHugePages with the number of faults.
./address_spaceperf stat -e page-faults,minor-faults,major-faults ./address_spacePRIMARY REFERENCES