Subtopic 3
Segments
Code Examples
Independent Copies of Memory
After fork(), the parent and child appear to have identical memory. But they are independent copies. A change made by the child does not affect the parent’s memory, and vice versa. This section shows exactly which segments are involved, with code to prove it.
local vars, return addr
malloc() memory
uninit globals = 0
init global/static vars
program code (R/O)
“Own copy” = copy-on-write until first write. Text segment = truly shared, never copied.
| Segment | Contents | C Example | After fork() |
|---|---|---|---|
| Text | Compiled machine code | main(){...} |
Shared (read-only) |
| Data (init) | Initialized globals & statics | int x = 5; |
Independent copy |
| BSS (uninit) | Uninit globals & statics (=0) | static int y; |
Independent copy |
| Heap | Dynamic memory | malloc(100) |
Independent copy |
| Stack | Local vars, function frames | int n = 3; |
Independent copy |
Directly from the textbook: child modifies global (data segment) and local (stack) variables:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
/* Allocated in data segment */
static int idata = 111;
int main(void)
{
/* Allocated in stack segment */
int istack = 222;
pid_t childPid;
switch (childPid = fork()) {
case -1:
perror("fork"); exit(EXIT_FAILURE);
case 0:
/* CHILD: multiply both by 3 */
idata *= 3; /* 111 * 3 = 333 */
istack *= 3; /* 222 * 3 = 666 */
break;
default:
/* PARENT: sleep to let child run first */
sleep(3);
break;
}
/* Both parent and child reach here */
printf("PID=%ld %s idata=%d istack=%d\n",
(long)getpid(),
(childPid == 0) ? "(child) " : "(parent)",
idata, istack);
exit(EXIT_SUCCESS);
}
PID=1235 (child) idata=333 istack=666PID=1234 (parent) idata=111 istack=222Child’s copies changed; parent’s originals untouched.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
int main(void)
{
/* Allocate heap memory BEFORE fork */
char *buf = malloc(64);
if (!buf) { perror("malloc"); exit(1); }
strcpy(buf, "original data");
printf("[Before fork] buf = \"%s\" at %p\n", buf, (void*)buf);
pid_t pid = fork();
if (pid == -1) { perror("fork"); exit(1); }
if (pid == 0) {
/* CHILD: modify heap memory */
strcpy(buf, "child modified");
printf("[Child PID=%d] buf = \"%s\" at %p\n",
getpid(), buf, (void*)buf);
free(buf);
_exit(0);
}
/* PARENT: sleep, then check its own copy */
sleep(1);
printf("[Parent PID=%d] buf = \"%s\" at %p\n",
getpid(), buf, (void*)buf);
/* Parent's buf is STILL "original data" */
free(buf);
wait(NULL);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
/* Print memory info from /proc/self/status */
void print_memory_info(const char *label)
{
char path[64], line[256];
FILE *f;
snprintf(path, sizeof(path), "/proc/%d/status", getpid());
f = fopen(path, "r");
if (!f) return;
printf("\n--- Memory for %s (PID=%d) ---\n", label, getpid());
while (fgets(line, sizeof(line), f)) {
/* Print VmRSS (Resident Set Size) and VmSize */
if (strncmp(line, "VmRSS", 5) == 0 ||
strncmp(line, "VmSize", 6) == 0 ||
strncmp(line, "VmData", 6) == 0 ||
strncmp(line, "VmStk", 5) == 0)
printf(" %s", line);
}
fclose(f);
}
/* Note: need #include <string.h> for strncmp */
#include <string.h>
int main(void)
{
/* Allocate 10 MB before fork */
char *big = malloc(10 * 1024 * 1024);
if (big) big[0] = 'A'; /* touch it to force allocation */
print_memory_info("Parent before fork");
pid_t pid = fork();
if (pid == -1) { perror("fork"); exit(1); }
if (pid == 0) {
print_memory_info("Child after fork");
/* Modify memory: triggers copy-on-write pages */
for (int i = 0; i < 10*1024*1024; i++) big[i] = 'B';
print_memory_info("Child after modifying memory");
free(big);
_exit(0);
}
wait(NULL);
print_memory_info("Parent after child exits");
free(big);
return 0;
}
gcc -o mem_demo mem_demo.cNo. After fork(), each process has its own independent copy of the data segment (due to copy-on-write). The child’s modification of the global variable creates a private copy for the child. The parent’s copy remains unchanged.
Yes. The text segment is read-only (program code doesn’t change at runtime). The kernel marks it read-only and both processes share the same physical pages. No copy is ever needed. This saves significant memory.
The child gets a copy-on-write copy of the parent’s heap. The virtual addresses look the same in both processes, but they point to different physical pages once either process modifies the memory. Both processes should independently free their copies (the child should free in the child, parent in the parent).
BSS (Block Started by Symbol) holds uninitialized global and static variables. They are automatically zero-initialized by the OS. In the binary file, BSS takes no space — only its size is stored. After fork(), child gets an independent copy just like the data segment.
Yes. /proc/<pid>/maps shows all memory mappings with addresses and permissions. /proc/<pid>/status shows VmSize (virtual), VmRSS (physical resident), VmData (data), VmStk (stack). /proc/self/ refers to the current process.
