Process Lifecycle Breakdown (Detailed Step-by-Step in English)

Example Scenario

  1. The shell (sh) process is running.
  2. sh creates a child process via fork().
  3. The child transforms into a new program, app, via exec().
  4. app is a small program, occupying 1 page for code/data and 1 page for its stack.
  5. During execution, app calls malloc(), causing its heap to grow by 2 physical pages.
  6. app finishes its task and calls exit().

In total, the app process uses 8 physical pages during its lifetime.

Let’s see how these pages are allocated and later deallocated.


Stage 1: The Birth of a Process (fork & exec)

When you type ./app and press Enter, the sh process creates a child, which then transforms into app.

Initial State

A minimal app process is born, requiring 6 physical pages in total.

1. fork() calls allocproc() – Allocating Basic Kernel Structures (4 pages)

Page Description
1 Trapframe: allocproc calls kalloc() to allocate a physical page for the process’s trapframe. It saves register states when switching between kernel and user mode.
2 L2 Page Table: allocproc calls proc_pagetable()uvmcreate()kalloc(), allocating a physical page for the root page table (L2).
3 L1 Page Table: proc_pagetable() maps the high-memory TRAMPOLINE. mappages()walk() finds no L1 table, so it calls kalloc() to create one.
4 L0 Page Table: walk() finds no L0 table in the new L1 table and again calls kalloc() to allocate a physical page for an L0 table.

2. exec() Loads the app Program – Allocating User Space (2 pages)

  • The child process (copy of sh) calls exec("app", ...).
  • exec discards the user memory and page tables copied from sh and creates a new user space.
Page Description
5 Code/Data Page: exec reads the executable, calls uvmalloc()kalloc() to allocate one physical page, and loads the program’s code/data.
6 User Stack: exec again calls uvmalloc()kalloc() to allocate one page for the initial user stack.

Summary of Stage 1

When app starts running, the kernel has allocated 6 physical pages:

  • 1 Trapframe
  • 3 Page Table Pages (L2, L1, L0)
  • 1 Code Page
  • 1 Stack Page

Stage 2: The Growth of a Process (malloc)

app executes and requests additional memory using malloc().

Growth State

app requests 8192 bytes (2 pages) of memory, increasing total allocation to 8 physical pages.

1. malloc() calls sbrk()

  • malloc(8192) detects insufficient memory in its pool.
  • It calls the sbrk(8192) system call to request more heap memory from the kernel.

2. sbrk() calls growproc()uvmalloc()

  • growproc calculates that 2 new physical pages are needed.
  • It calls uvmalloc(2 * PGSIZE).
Page Description
7 Heap Page #1: Inside uvmalloc, kalloc() allocates one physical page.
8 Heap Page #2: kalloc() allocates another physical page.

uvmalloc then calls mappages() to establish new mappings, linking these pages to the top of the process’s heap.

Summary of Stage 2

app now occupies 8 physical pages in total:

  • 6 initial pages
  • 2 heap pages allocated via malloc()

Stage 3: The Demise of a Process (exit)

When app finishes, it calls exit().

The kernel now reclaims all its resources.

Deallocation Order

1. freeproc() – Freeing Non-Page-Table Memory (1 page)

  • exit() executes freeproc(p).
  • freeproc first releases non-page-table resources.
Page Description
1 Trapframe: freeproc calls kfree(p->trapframe) to reclaim this page.

2. proc_freepagetable() – Freeing All User and Page Table Pages (7 pages)

freeproc then calls proc_freepagetable(p->pagetable, p->sz), which performs two major steps:


Step A: uvmunmap() – Reclaiming All User Data Pages (4 pages)

  • proc_freepagetable calls uvmunmap to unmap all user-space mappings.
  • uvmunmap iterates over virtual addresses from 0 to p->sz.
Page Description
2 Code/Data: uvmunmap finds the mapping and calls kfree().
3 User Stack: Found and freed via kfree().
4–5 Heap Pages: Both heap pages are unmapped and freed.

After this step, all user-space data pages (code, stack, heap) have been reclaimed.


Step B: uvmfree() – Reclaiming the Page Table Pages (3 pages)

After uvmunmap returns, proc_freepagetable calls uvmfree to free the page table hierarchy.

Page Description
6 L0 Page Table: uvmfree recurses to the lowest level and calls kfree().
7 L1 Page Table: Returns from recursion and frees the L1 table.
8 L2 Page Table: After returning, proc_freepagetable frees the root table (L2).

If the user space were larger, multiple L0 or L1 tables would be freed here as well.


Final Summary

Deallocation order:

  1. Trapframe page
  2. All user data pages (code, stack, heap, etc.)
  3. Page table pages (bottom-up: L0 → L1 → L2)

At this point, all 8 physical pages used by the app process have been fully released back to the system —

ready to serve the next process.