When a program executes, the memory addresses it works with are not physcial hardware locations. This distinction becomes clear through the behavior of fork().
Consider the following demonstration. A global integer is initialized, and then a new process is created:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int shared_val = 0;
int main()
{
pid_t pid = fork();
if (pid < 0) {
perror("fork");
return 1;
}
if (pid == 0) { // child path
printf("child[%d]: value = %d, address = %p\n", getpid(), shared_val, &shared_val);
} else { // parent path
printf("parent[%d]: value = %d, address = %p\n", getpid(), shared_val, &shared_val);
}
sleep(1);
return 0;
}
Both parent and child print the same address for shared_val. Now modify the variable in the child before the parent reads it:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int shared_val = 0;
int main()
{
pid_t pid = fork();
if (pid < 0) {
perror("fork");
return 1;
}
if (pid == 0) {
shared_val = 200;
printf("child[%d]: value = %d, address = %p\n", getpid(), shared_val, &shared_val);
} else {
sleep(2);
printf("parent[%d]: value = %d, address = %p\n", getpid(), shared_val, &shared_val);
}
sleep(1);
return 0;
}
Observe: both processes still report the identical address, yet the values differ. This shows that the addresses visible to user space are not direct physical memory locations. They are virtual addresses—abstractions provided by the operating system. In C and C++, every pointer you manipulate is a virtual address. The kernel alone manages the mapping between virtual and physical memory.
This is the foundation of the process address space. Each process receives its own private virtual address space, as illustrated below:
- The same virtual address (e.g.,
0x60104c) in two different processes can independently point to distinct physical frames. -1 When a child process writes to a shared variable afterfork(), the kernel implements copy‑on‑write: the physical page containing the variable is duplicated, and the child’s virtual mapping is updated to point to the new physical frame, while the parent retains the original mapping.
Thus,16 the apparent contradiction—identical virtual address, different content—is resolved by the kernel’s per‑process page tables. This isolation is fundamental to process protection, stability, and memory management in Linux.