1
[Link]
Professor, CSE, UEC
[Link], CSE 06-02-2026
Memory management is a core function of an OS,
It controls and coordinates the use of a computer’s main
memory (RAM).
It ensures that memory is efficiently allocated to processes,
used properly during execution, and released when no
longer needed.
The OS acts as a manager between programs and physical
memory,
deciding which process gets how much memory, when, and
for how long.
[Link], CSE 06-02-2026 2
Keep track of the resource (memory). What parts are in use
and by whom? What parts are not in use (called free)?
If multiprogramming, decide which process gets memory,
when it gets it, and how much.
Allocate the resource (memory) when the processes request
it.
Reclaim the resource (memory) when the process no longer
needs it or has been terminated.
[Link], CSE 06-02-2026 3
Address space is an abstraction of memory provided to a
running program.
It represents the set of memory addresses that a process can
access during its execution.
Instead of directly interacting with physical memory, a
program operates within its own logical view of memory,
which simplifies programming and improves system safety.
Each process in a system is given a separate address space,
ensuring that one process cannot interfere with the memory
of another.
This isolation is essential for system stability and security.
[Link], CSE 06-02-2026 4
Figure 13.3 illustrates a
process address space,
which is the logical view of
memory provided by the os to
a running program.
Physical memory may be
located elsewhere,
the program assumes that it
occupies a continuous block
of memory ranging from 0 KB
to 16 KB.
[Link], CSE 06-02-2026 5
1. Program Code Segment (0 KB – 1 KB)
Located at the lowest memory addresses
Contains the executable instructions of the program
This segment is static, meaning its size does not change during
execution
It is usually read-only to prevent accidental modification
2. Heap Segment (starts at 1 KB)
Used for dynamic memory allocation
Memory requested at runtime (e.g., using malloc() or new) is
allocated here
In the given figure, the heap grows downward
Managed explicitly by the programmer
[Link], CSE 06-02-2026 6
3. Free Space (Middle Region)
The shaded region represents unused or free memory
This space allows both the heap and the stack to grow dynamically
Efficient memory management ensures that these two regions do
not collide
4. Stack Segment (starts at 16 KB)
Located at the highest memory addresses
Stores:
Local variables, Function parameters, Return addresses
The stack grows upward as function calls increase
Automatically managed by the system
[Link], CSE 06-02-2026 7
The heap and stack grow in opposite directions
This arrangement maximizes memory utilization and
flexibility
If the heap and stack meet, a stack overflow or heap overflow
may occur
The addresses shown (0 KB to 16 KB) are virtual addresses
The os, using hardware support (MMU), maps these virtual
addresses to physical memory locations
This mechanism enables memory virtualization, protection,
and process isolation
[Link], CSE 06-02-2026 8
The figure illustrates how
multiple processes and the os
are stored in main memory
(RAM) at the same time.
This arrangement
demonstrates
multiprogramming,
where several processes
coexist in memory and share
system resources.
[Link], CSE 06-02-2026 9
1. Operating System in Memory
OS occupies the lowest portion of memory (from 0 KB to 64
KB).
This region contains OS code, data structures, and system
routines.
The OS remains resident in memory to manage processes,
memory, and hardware.
[Link], CSE 06-02-2026 10
2. User Processes in Memory
remaining memory is divided among three user processes:
Process C
Loaded between 128 KB and 192 KB
Contains its own code, data, stack, and heap
Process B
Loaded between 192 KB and 256 KB
Completely isolated from other processes
Process A
Loaded between 320 KB and 384 KB
Runs independently in its own allocated region
[Link], CSE 06-02-2026 11
Each process is placed at a different physical memory location,
but each believes it starts at address 0 in its own virtual address
space.
3. Free Memory Regions
The shaded areas represent free (unused) memory
These gaps are created due to:
Process termination
Variable-sized memory allocation
Such gaps may lead to external fragmentation in contiguous
memory allocation systems
[Link], CSE 06-02-2026 12
Each process assumes it is loaded at address 0
The OS and hardware translate these virtual addresses to
the actual physical addresses shown
This abstraction is known as memory virtualization
[Link], CSE 06-02-2026 13
Memory API is a collection of system calls and library
functions that allow programs to allocate, access, protect, share,
and release memory.
These APIs provide a safe interface between applications and
the operating system’s memory management subsystem.
Why Memory API is Needed?
Programs need memory at runtime
Physical memory details must be hidden from applications
Ensures protection and isolation
Supports virtual memory
[Link], CSE 06-02-2026 14
In running a C program, there are two types of memory that are
allocated.
The first is called stack memory, and allocations and deallocations of
it are managed implicitly by the compiler, for this reason it is
sometimes called automatic memory.
Declaring memory on the stack in C is easy.
For example, let’s say you need some space in a function func() for an
integer, called x.
To declare such a piece of memory, you just do something like this:
void func() {
int x; // declares an integer on the stack
...
}
[Link], CSE 06-02-2026 15
The compiler does the rest, making sure to make space on the stack
when you call into func().
When your return from the function, the compiler deallocates the
memory.
Second type of memory, called heap memory, where all allocations
and deallocations are explicitly handled by you, the programmer.
Example of how one might allocate a pointer to an integer on the
heap:
void func() {
int *x = (int *) malloc(sizeof(int));
...
}
[Link], CSE 06-02-2026 16
First, you might notice that both stack and heap allocation
occur on this line:
first the compiler knows to make room for a pointer to an
integer when it sees (int *x);
subsequently, when the program calls malloc(), it requests
space for an integer on the heap;
the routine returns the address of such an integer (upon
success, or NULL on failure), which is then stored on the stack
for use by the program.
[Link], CSE 06-02-2026 17
malloc() (memory allocation) is a standard library function used
to dynamically allocate memory at runtime.
It allocates a specified number of bytes from the heap of a
process and returns a pointer to the beginning of the allocated
memory block.
Syntax
void* malloc(size_t size);
The program calls malloc(size)
malloc() requests memory from the heap
The os checks whether sufficient memory is available
If successful, malloc() returns a pointer to the allocated memory
If allocation fails, it returns NULL
[Link], CSE 06-02-2026 18
The allocated memory:
Is contiguous
Is uninitialized (contains garbage values)
Remains allocated until it is explicitly freed
Example
int *arr;
arr = (int*) malloc(10 * sizeof(int));
if (arr == NULL)
{ // Memory allocation failed
}
[Link], CSE 06-02-2026 19
To free heap memory that is no longer in use, programmers
simply call free():
int *x = malloc(10 * sizeof(int));
...
free(x);
The routine takes one argument, a pointer that was returned by
malloc().
the size of the allocated region is not passed in by the user,
and must be tracked by the memory-allocation library itself.
[Link], CSE 06-02-2026 20
There are a number of common errors that arise in the use of
malloc() and free().
1. Forgetting To Allocate Memory
Many routines expect memory to be allocated before you call them.
For example, the routine strcpy(dst, src) copies a string from a source
pointer to a destination pointer.
However, if you are not careful, you might do this:
char *src = "hello";
char *dst; // oops! unallocated
strcpy(dst, src); // segfault and die
When you run this code, it will likely lead to a segmentation fault3
[Link], CSE 06-02-2026 21
In this case, the proper code might instead look like this:
char *src = "hello";
char *dst = (char *) malloc(strlen(src) + 1);
strcpy(dst, src); // work properly
[Link], CSE 06-02-2026 22
2. Not Allocating Enough Memory (Buffer Overflow)
Not allocating enough memory occurs when the destination
buffer is smaller than the data being copied into it.
This often leads to a buffer overflow,
which causes undefined behavior such as crashes, data corruption,
or security vulnerabilities.
Example:
char *src = "hello";
char *dst = (char *) malloc(strlen(src)); // too small!
strcpy(dst, src); // ERROR
[Link], CSE 06-02-2026 23
Correct Code ✅
char *dst = (char *) malloc(strlen(src) + 1);
if (dst == NULL)
{ // handle error}
strcpy(dst, src);
[Link], CSE 06-02-2026 24
3. Forgetting to Initialize Allocated Memory
Forgetting to initialize allocated memory occurs when a
program correctly allocates memory using malloc(),
but fails to assign valid values to the allocated memory before
reading or using it.
Since malloc() does not initialize memory, the contents of the
allocated region are undefined.
Correct code:
int *arr = malloc(5 * sizeof(int));
[Link], CSE 06-02-2026 25
4. Forgetting to Free Memory
means allocating memory using malloc()
but not releasing it using free() after it is no longer needed.
This problem is called a memory leak.
What is a Memory Leak?
Memory is allocated but never returned to the system
Over time, unused memory keeps increasing
Eventually, the system runs out of memory
Example:
int *p = malloc(100 * sizeof(int));
[Link], CSE free(p); 06-02-2026 26
5. Freeing Memory Before You Are Done With It
Sometimes a program will free memory before it is finished using it;
Such a mistake is called a dangling pointer
The subsequent use can crash the program, or overwrite valid
memory
(e.g., you called free(), but then called malloc() again to allocate
something else, recycles the errantly-freed memory).
Example:
free(p);
p = malloc(sizeof(int)); // memory may be reused
[Link], CSE 06-02-2026 27
6. Freeing Memory Repeatedly
Freeing memory repeatedly means calling free() more than
once on the same memory block.
This error is known as a double free.
A double free causes undefined behavior, because once
memory is freed, it no longer belongs to the program.
Example code:
int *p = malloc(sizeof(int));
free(p); // first free – OK
free(p); // second free – ERROR (double free)
[Link], CSE 06-02-2026 28
7. Calling free() Incorrectly
Calling free() incorrectly means passing a pointer to free()
that was not returned by malloc() (or calloc() / realloc()).
This is called an invalid free, and it leads to undefined behavior.
Example code:
int *p = malloc(10 * sizeof(int));
free(p + 1); // ERROR
Correct usage:
int *p = malloc(sizeof(int));
free(p);
p = NULL;
[Link], CSE 06-02-2026 29
Address translation is the process by which the CPU-
generated virtual (logical) address
is converted into a physical address in main memory by the
hardware (MMU – Memory Management Unit).
Note:
Programs never access physical memory directly.
They use virtual addresses, and the OS + hardware handle the
conversion.
[Link], CSE 09-02-2026 30
Why Address Translation is Needed
Each process thinks it has its own private memory
Protects one process from accessing another’s memory
Allows efficient memory sharing and relocation
Supports virtual memory
[Link], CSE 09-02-2026 31
Imagine there is a process whose
address space as indicated in Figure
15.1.
loads a value from memory,
increments it by 3, and then stores the
value back into memory.
Consider the C statement:
x = x + 3;
[Link], CSE 09-02-2026 32
The compiler converts this into the following x86 assembly:
128: movl 0x0(%ebx), %eax; load x into eax
132: addl $0x03, %eax; add 3
135: movl %eax, 0x0(%ebx); store back to x
Assumptions:
Register EBX contains the address of variable x
Variable x is located at 15 KB in the process’s address space
Instructions start at address 128
[Link], CSE 09-02-2026 33
Process Address Space Layout (Virtual)
From the process’s point of view:
Address space starts at 0
Maximum size = 16 KB
Code segment near the top
Stack near the bottom
Example values:
Instruction at address 128
Variable x at address 15 KB
Initial value of x = 3000
Important: All addresses used by the program (128, 132, 135, 15 KB)
are virtual addresses.
[Link], CSE 09-02-2026 34
Memory Accesses Generated by the Program
When the program runs, it generates the following virtual memory
accesses:
1. Fetch instruction at virtual address 128
2. Load data from virtual address 15 KB
3. Fetch instruction at virtual address 132
4. Execute add (no memory access)
5. Fetch instruction at virtual address 135
6. Store data to virtual address 15 KB
7. From the program’s perspective, everything is within 0 → 16 KB.
[Link], CSE 09-02-2026 35
However, to virtualize memory, the OS wants to place the process
somewhere else in physical memory, not necessarily at address 0.
The Core Problem
OS does NOT want to load every process starting at physical address 0.
In the example: OS occupies 0–16 KB
Process is placed starting at physical address 32 KB
So:❓ How can a program that thinks it is running at address 0
actually run at physical address 32 KB without knowing it?
This is exactly why address translation is required.
[Link], CSE 09-02-2026 36
Physical memory is divided into
16 KB slots
So the process’s virtual address
0 actually maps to physical
address 32 KB.
The other two slots are free (16
KB-32 KB and 48 KB-64 KB)
[Link], CSE 09-02-2026 37
Dynamic relocation is a hardware technique
that allows the OS to load a process anywhere in physical
memory, while the process thinks it starts at address 0.
This is done using two special CPU registers:
• Base register
• Bounds (Limit) register
[Link], CSE 09-02-2026 38
1. Base Register
• Stores the starting physical address of the process
• Used to translate virtual addresses to physical addresses
2. Bounds (Limit) Register
• Stores the size of the process address space
• Used to protect memory
• Ensures the process does not access memory outside its
area
[Link], CSE 09-02-2026 39
Key Idea
• Program is written as if it starts at address 0
• OS decides where to place it in physical memory
• Hardware automatically converts addresses at runtime
Address Translation Rule
Physical Address = Virtual Address + Base
This conversion is done by the MMU
[Link], CSE 09-02-2026 40
Example
• Process size = 16 KB
• Base register = 32 KB
• Bounds register = 16 KB
Instruction Fetch Example
Virtual instruction address = 128
Physical Address = 32 KB (32768) + 128 = 32896
Note: 1 KB = 1024 bytes
[Link], CSE 09-02-2026 41
Data Access Example
Virtual address of variable x = 15 KB
Physical Address = 32 KB + 15 KB = 47 KB
Process thinks it accessed 15 KB
Hardware actually accesses 47 KB
[Link], CSE 09-02-2026 42
Protection Using Bounds Register
Before adding the base:
CPU checks: 0 ≤ Virtual Address < Bounds
If invalid:
CPU raises an exception
Process is terminated
Small Translation Example
Process size = 4 KB
Base address = 16 KB
[Link], CSE 09-02-2026 43
Imagine a process with an address space of size 4 KB
[Link], CSE 09-02-2026 44
Segmentation is a memory management technique
where a process is divided into logical parts, called segments.
Each segment has:
• Its own base register (starting physical address)
• Its own bounds/limit register (size of the segment)
This is why it is called generalized base and bounds.
[Link], CSE 09-02-2026 45
A program is usually divided into:
• Code segment – program instructions
• Heap segment – dynamically allocated memory
• Stack segment – function calls and local variables
Each segment is managed independently.
Why Segmentation Is Needed
• Avoids wasting memory
• Only used memory is placed in physical memory
• Different segments can be placed in different locations
• Provides better protection
[Link], CSE 09-02-2026 46
Example
[Link], CSE 09-02-2026 47
How Address Translation Works
Physical Address = Base + Offset
Where:
Offset = Virtual Address − Start of Segment
Before translation:
Offset < Segment Size (bounds check)
[Link], CSE 09-02-2026 48
Example 1:
Code Segment Access:
Virtual address = 100
Code segment starts at virtual address 0
Base = 32 KB
Offset: 100 − 0 = 100
Physical address: 32 KB + 100 = 32868
Valid memory access
[Link], CSE 09-02-2026 49
Example 2: Heap Segment Access
Heap starts at virtual address 4 KB (4096)
Virtual address = 4200
Heap base = 34 KB (34816)
Offset: 4200 − 4096 = 104
Physical address: 34816 + 104 = 34920
Correct address
[Link], CSE 09-02-2026 50
Example 3: Invalid Access (Segmentation Fault)
• Virtual address = 7 KB
• Heap size = 2 KB
• Heap valid range = 4 KB to 6 KB
Address is outside the segment
➡ CPU raises an exception
➡ OS terminates the process
This is called a segmentation fault.
[Link], CSE 09-02-2026 51
Why Sharing Is Needed?
Many processes often run the same program (example: many users
running the same editor).
If each process keeps its own copy of code, memory is wasted.
Solution: Share the code segment among processes.
How Sharing Works in Segmentation?
Segmentation already divides memory into:
• Code
• Heap
• Stack
Now we add protection bits for each segment.
[Link], CSE 10-02-2026 52
Protection Bits (Hardware Support)
Each segment has protection bits that specify what is allowed:
Read (R)
Write (W)
Execute (X)
Examples:
Code segment → Read + Execute (RX)
Heap segment → Read + Write (RW)
Stack segment → Read + Write (RW)
[Link], CSE 10-02-2026 53
How Code Sharing Is Achieved?
Code segment is marked read-only
Same physical code segment is mapped into multiple processes
No process can modify it
✔ Saves memory
✔ Maintains protection
✔ Processes still think memory is private
[Link], CSE 10-02-2026 54
Two Processes Sharing Code
Process A code segment → Base
= 32 KB
Process B code segment → Base
= 32 KB
Both point to the same physical
memory for code.
If: Process A tries to write to
code → ❌ exception
Process B tries to execute code
→ ✔ allowed
[Link], CSE 10-02-2026 55
When a memory access occurs, the MMU checks:
Is the address within bounds?
Is the operation allowed (R/W/X)?
If either fails:
➡ Hardware raises an exception
➡ OS handles the error (often terminates the process)
What Happens Without Protection Bits?
One process could modify shared code
Other processes would be affected
System becomes unsafe
[Link], CSE 10-02-2026 56
Paging divides memory into fixed-size blocks instead of variable-
size segments.
Virtual memory → divided into pages
Physical memory → divided into frames
Page size = frame size
Example: Virtual Address Space
Size = 64 bytes
Page size = 16 bytes
Number of pages = 4 (Pages 0–3)
[Link], CSE 10-02-2026 57
Physical Memory
Divided into 8 frames
OS places virtual pages into
free physical frames:
[Link], CSE 10-02-2026 58
Os keeps a per-process data structure known as a page table.
The major role of the page table is to store address
translations for each of the virtual pages of the address
space,
thus letting us know where in physical memory they live.
Example:
VP 0 → PF 3
VP 1 → PF 7
VP 2 → PF 5
VP 3 → PF 2
[Link], CSE 10-02-2026 59
Virtual Address Format in Paging
Given:
Address space = 64 bytes → 6-bit address
Page size = 16 bytes → 4-bit offset
So virtual address is split as:| VPN (2 bits) | Offset (4 bits) |
Va5 is the highest-order bit of the virtual address
Va0 the lowest order bit.
Because we know the page size (16 bytes)
[Link], CSE 10-02-2026 60
we can further divide the virtual address as follows:
When a process generates a virtual address,
the OS and hardware must combine to translate it into a
meaningful physical address.
[Link], CSE 10-02-2026 61
Example
Given instruction:
movl 21, %eax
Step 1: Convert to binary 21 = 010101
Step 2: Split into VPN and Offset
VPN 01 Offset 0101
VPN = 01 (1) Offset = 0101 (5)
Step 3: Page Table Lookup
From page table: VP 1 → PF 7
PF 7 in binary = 111
[Link], CSE 10-02-2026 62
Step 4: Form Physical Address
Replace VPN with PFN, keep offset unchanged:
PFN 111 Offset 0101
Final physical address:1110101 = 117 (decimal) (See Fig.18.2)
Correct memory location accessed
Why Offset Is Not Changed
Offset represents the byte inside the page
Same offset applies in both virtual page and physical frame
[Link], CSE 10-02-2026 63
A page table is a data structure used by the OS to translate:
Virtual Address → Physical Address
Each process has its own page table.
Instead of dealing with the full address, it works with:
VPN – Virtual Page Number
PFN – Physical Frame Number
Think of it like a lookup table:
Index → Virtual Page Number (VPN)
Value → Page Table Entry (PTE)
[Link], CSE 11-02-2026 64
Linear Page Table
The simplest page table is a linear page table.
It is just an array
Each array entry is a Page Table Entry (PTE)
OS uses the VPN as the index
Example
PageTable[VPN] → PTE → PFN
So, if VPN = 5
OS looks at PageTable[5] to find where that page is in
physical memory.
[Link], CSE 10-02-2026 65
Each PTE contains:
The physical frame number (PFN)
Some control bits (very important!)
1. Valid Bit
Tells whether the page is valid or not
If invalid → accessing it causes a trap (error) to OS
Used to support sparse address space
Unused pages are marked invalid
Saves physical memory
[Link], CSE 10-02-2026 66
2. Protection Bits
Control how a page can be used:
Read (R) – Can read?
Write (W) – Can write?
Execute (X) – Can execute instructions?
If a program violates this → trap to OS
3. Present Bit
1 → Page is in physical memory
0 → Page is on disk (swapped out)
Used in virtual memory & swapping
[Link], CSE 10-02-2026 67
4. Dirty Bit
Indicates whether the page was modified
If dirty = 1 → must be written back to disk before replacement
5. Accessed / Reference Bit
Set when page is used
Helps OS decide which page to remove (page replacement)
[Link], CSE 10-02-2026 68
Example
Virtual Page 0 → Physical Frame 3
Virtual Page 1 → Physical Frame 7
Virtual Page 2 → Physical Frame 5
Virtual Page 3 → Physical Frame 2
VPN PFN
Page Table looks like: 0 3
1 7
2 5
3 2
[Link], CSE 11-02-2026 69
Figure 18.5 shows an example page table entry from the x86
architecture.
Present bit (P); read/write bit (R/W), determines if writes are allowed to
this page ; user/supervisor bit (U/S), determines if user-mode processes
can access the page;
a few bits (PWT, PCD, PAT, and G) that determine how hardware caching
works for these pages;
Accessed bit (A) and a dirty bit (D); page frame number (PFN)
[Link], CSE 11-02-2026 70
TLB is a small, fast cache inside the CPU that stores recent
virtual-to-physical address translations.
TLB = Cache for page table entries
Why do we need a TLB?
Without a TLB:
CPU generates a virtual address
OS looks up the page table in memory
Then accesses the actual data in memory
This means two memory accesses for every instruction → slow
[Link], CSE 10-02-2026 71
With TLB (Much Faster )
CPU generates a virtual address
TLB is checked first
If found → physical address obtained immediately
If not found → page table in memory is used
This saves time and memory accesses.
[Link], CSE 10-02-2026 72
TLB Hit
Required translation is found in TLB
Very fast
Physical address generated directly
TLB Miss
Translation not found in TLB
Page table is accessed from main memory
Entry may be added to TLB
[Link], CSE 10-02-2026 73
It depends on the system architecture.
There are two possible ways a TLB miss is handled:
1. Hardware-Managed TLB (e.g., x86)
Handled by hardware (CPU)
What happens?
CPU checks the TLB
TLB miss occurs
Hardware automatically walks the page table
Finds the page table entry (PTE)
Loads it into the TLB
Continues execution
OS is not involved unless there is a page fault
[Link], CSE 10-02-2026 74
2. Software-Managed TLB (e.g., MIPS, SPARC)
Handled by the Operating System
What happens?
CPU detects a TLB miss
CPU raises a TLB miss exception
Control transfers to the OS
OS searches the page table
OS updates the TLB
Execution resumes
Slower than hardware handling, but more flexible
[Link], CSE 10-02-2026 75
[Link], CSE 10-02-2026 76