Memory Regions - Virtual Memory
#memory | #lowlevel | #cacheVirtual memory is not a type of physical memory nor a memory region or segment, but rather a memory management technique that provides an "illusion" of a very large memory space by using disk space to simulate additional RAM. If your program exceeds available physical RAM, the OS moves data to disk-based swap space. This helps prevent crashes but is slower than real RAM and depends on storage space.
RAM stands for Random Access Memory. It's a type of computer memory that is used to store data and machine code that is actively being used or processed. RAM allows for quick read and write access to data, making it essential for a computer's performance. Unlike storage devices (such as hard drives or SSDs), RAM is volatile, meaning it loses all its data when the computer is turned off.
— Perplexity.ai
Key characteristics
- It enables processes to use more memory than what is physically available on the system;
- Swapping or paging is used to move data between RAM and the disk as needed;
- Allows process isolation and protection, preventing one program from interfering with another;
- Provides each process with its own virtual address space, simplifying memory allocation and avoiding address conflicts;
- Supports memory-mapped files, allowing files to be treated as part of a process's memory space for efficient file I/O;
- Helps reduce fragmentation in physical memory by abstracting allocation details from processes;
- Facilitates easier implementation of multitasking and multiprocessing in modern operating systems;
- Improves system stability by catching invalid memory access and isolating faults at the process level.
Limitations
- Usually slower than the physical memory, especially on non-SSD drives with small capacity;
- Heavy swapping can degrade overall system performance (also known as "thrashing");
- May shorten the lifespan of SSDs due to excessive read/write cycles caused by swapping;
- Increases latency for memory access, which can affect real-time or performance-sensitive applications;
- Requires disk space to function—if the disk is full, virtual memory can't expand and may cause system instability;
- Over-reliance on virtual memory may hide poor memory management in applications, leading to inefficient software;
- Security risks may arise if swap files are not encrypted, potentially exposing sensitive data stored temporarily on disk.
Example 1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#define PAGE_SIZE 16 // Small page size for simulation
#define RAM_PAGES 2 // Simulated physical memory (2 pages)
#define SWAP_FILE "swapfile" // Swap space file
char ram[RAM_PAGES][PAGE_SIZE]; // Simulated RAM
int page_table[RAM_PAGES] = {-1, -1}; // Tracks which virtual page is in RAM
void swap_out(int virtual_page) {
int fd = open(SWAP_FILE, O_WRONLY | O_CREAT, 0644);
lseek(fd, virtual_page * PAGE_SIZE, SEEK_SET);
write(fd, ram[0], PAGE_SIZE); // Swap out first page (FIFO)
close(fd);
printf("Swapped out virtual page %d to disk.\n", virtual_page);
}
void swap_in(int virtual_page) {
int fd = open(SWAP_FILE, O_RDONLY);
if (fd < 0) {
printf("Error opening swap file!\n");
exit(1);
}
lseek(fd, virtual_page * PAGE_SIZE, SEEK_SET);
read(fd, ram[1], PAGE_SIZE); // Load into second RAM slot
close(fd);
printf("Swapped in virtual page %d from disk.\n", virtual_page);
}
void access_memory(int virtual_page) {
int in_ram = -1;
for (int i = 0; i < RAM_PAGES; i++) {
if (page_table[i] == virtual_page) {
in_ram = i;
break;
}
}
if (in_ram == -1) {
printf("Page fault! Virtual page %d not in RAM.\n", virtual_page);
swap_out(page_table[0]); // Swap out oldest page (FIFO)
page_table[0] = -1; // Mark as swapped out
swap_in(virtual_page);
page_table[1] = virtual_page;
} else {
printf("Virtual page %d is already in RAM (slot %d).\n", virtual_page, in_ram);
}
}
int main() {
printf("Simulating Virtual Memory...\n");
access_memory(0);
access_memory(1);
access_memory(2); // This will cause a page fault and swap
return 0;
}
This simple C program simulates how virtual memory works when the physical RAM isn't enough. It uses two small memory pages (arrays) to represent RAM and stores overflow pages in a file on disk, which acts as swap space. When a program tries to access a virtual page that's not in RAM, the system swaps out an old one and loads the new one from disk—this is called a page fault.
The function access_memory
checks if a given virtual page is already loaded in RAM. If not, it triggers a simulated page fault. The program then swaps out the oldest page using swap_out
, and loads the required one using swap_in
. The RAM is managed using a fixed-size array and a simple FIFO (first-in, first-out) replacement policy—meaning the oldest page gets kicked out first.
This model doesn't represent all the complexity of real operating systems, but it does give a hands-on understanding of how virtual memory lets a program use more memory than physically available. It also shows the cost—moving data to and from disk is way slower than using RAM directly. That's why relying too much on swap in real systems can make things slow.
Virtual memory system diagram
+-------------------------+ +--------------------------+
| Logical Memory | | Physical Memory |
| (Virtual Addresses) | | (Main Memory) |
+-------------------------+ +--------------------------+
| Page 0 → | ─────┐ | Frame 3 ← Page 0 |
| Page 1 → | ├─>| Frame 1 ← Page 1 |
| Page 2 → | │ | Frame 5 ← Page 2 |
| Page 3 → | │ | Frame 6 ← Page 3 |
+-------------------------+ │ +--------------------------+
│
Address Translation │
via Page Table │
│
+-------------------------+ │
| Page Table | ◄─────┘
+-------------------------+
| Page 0 → Frame 3 |
| Page 1 → Frame 1 |
| Page 2 → Frame 5 |
| Page 3 → Frame 6 |
+-------------------------+
|
| (Page Fault if not in table)
v
+-------------------------+
| Backing Store |
| (Secondary Storage) |
+-------------------------+
| Page 4 |
| Page 5 |
| ... |
+-------------------------+
Key takeaway
- Virtual addresses are broken into Pages, which get translated via the Page Table.
- If a Page is not in memory, it's fetched from the Backing Store.
- Pages are mapped into available frames in physical memory.
On-demand texture streaming
Talking about virtual memory this way is a bit boring, so let's spice it up with an exciting real-world example a la AAA Games.
This is a technique used in video games and graphics applications to load textures into memory only when needed, rather than loading everything at once. It helps manage memory efficiently, especially for large textures that may not be used all the time.
Imagine a large open-world game where loading every asset at once is impossible. You need to stream textures or models on demand as the player moves through the world. Let's simulate this using mmap
and a custom paging system in C. This is similar to what engines like Unreal and Unity do behind the scenes!
Illustrative scenario
- You have a huge "virtual world" file with terrain or texture tiles.
- You load only the needed tiles into memory using
mmap()
— as the player "moves" across the world.
Example 2
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#define TILE_SIZE 4096 // 4 KB per tile
#define WORLD_SIZE 1024 // Number of tiles (simulate a big world)
#define VIEW_RADIUS 2 // How many tiles around the player to load
#define FILENAME "world.dat"
void load_visible_tiles(int player_pos, char **loaded_tiles, int fd) {
for (int i = -VIEW_RADIUS; i <= VIEW_RADIUS; i++) {
int tile_index = player_pos + i;
if (tile_index < 0 || tile_index >= WORLD_SIZE) continue;
off_t offset = tile_index * TILE_SIZE;
loaded_tiles[i + VIEW_RADIUS] = mmap(NULL, TILE_SIZE, PROT_READ, MAP_PRIVATE, fd, offset);
if (loaded_tiles[i + VIEW_RADIUS] == MAP_FAILED) {
perror("mmap");
exit(1);
}
printf("Loaded tile %d at memory %p\n", tile_index, loaded_tiles[i + VIEW_RADIUS]);
}
}
void unload_tiles(char **loaded_tiles) {
for (int i = 0; i < VIEW_RADIUS * 2 + 1; i++) {
if (loaded_tiles[i]) {
munmap(loaded_tiles[i], TILE_SIZE);
loaded_tiles[i] = NULL;
}
}
}
int main() {
// Simulate a big world file
int fd = open(FILENAME, O_RDWR | O_CREAT, 0600);
if (fd < 0) { perror("open"); return 1; }
// Stretch world file to simulate gigabytes of data
off_t total_size = WORLD_SIZE * TILE_SIZE;
lseek(fd, total_size - 1, SEEK_SET);
write(fd, "", 1);
// Simulated player moving
char *loaded_tiles[VIEW_RADIUS * 2 + 1] = {0};
for (int player = 100; player < 105; player++) {
printf("\nPlayer at tile %d\n", player);
unload_tiles(loaded_tiles);
load_visible_tiles(player, loaded_tiles, fd);
usleep(500000); // Simulate time passing
}
close(fd);
return 0;
}
What makes this exciting
- You're simulating a modern game engine feature: on-demand loading of assets using memory-mapped I/O.
- No malloc, no I/O reads—the OS handles page faults and demand loading, just like in AAA engines.
- Scale: You could simulate gigabytes of terrain or textures and let the OS handle memory.
- With
MAP_NORESERVE
,MADV_RANDOM
, orMADV_SEQUENTIAL
, you can tune performance like a systems-level pro. - On modern hardware, memory-mapped I/O uses the page cache—so this hits SSD speed without reads or
memcpy
.
Possible extensions for your simulation
- Direct access to GPU-mapped memory using
mmap()
combined withDMA-buf
. - Use OS-level prefetching hints with
madvise()
to guide the kernel based on expected access patterns. - Implement multi-threaded decompression of memory-mapped regions to load large datasets efficiently in background threads.
- Simulate large terrain or texture streaming by mapping virtual pages backed by a file, and triggering page loads manually.
- Measure fault handling overhead—see how virtual memory behaves under load when scaling your simulation to hundreds of pages.
Game engines using similar technique
Many modern game engines use similar techniques to manage large assets efficiently. Here are a few examples:
Unreal Engine - Streaming Virtual Texturing
Unreal's Streaming Virtual Texturing (SVT) streams texture tiles on demand using paging techniques similar to virtual memory. This allows streaming only the visible portions of textures, improving performance in large open worlds. [1]
Elden Ring & Game Virtual Memory Usage
PC gamers have reported stuttering and crashes in large-scale open-world games like Elden Ring due to virtual memory (page file) being exhausted. Re-enabling or increasing the page file dramatically improves stability and performance. [2]
Unreal Editor & Large Landscapes
Developers using UE5 with massive landscapes often have to increase Windows pagefile size (e.g., 64-100 GB) to avoid crashes during tasks like terrain imports or lighting builds. [3]
Technique usage summary
Usage Scenario | Engine/Game | Virtual Memory Role |
---|---|---|
Streaming texture tiles on-demand |
Unreal Engine SVT | Efficient paging-based asset streaming |
Handling large terrain, heavy operations |
UE5 | Requires massive page file to support workspace |
Stability & performance in open-worlds |
Elden Ring, GTA | Pagefile prevents stuttering/crashes when RAM is full |
Modern game engines like Unreal use paging mechanisms under the hood to manage texture and map streaming—a direct application of virtual memory techniques. Also, in large-world consoles/PC gaming, OS-level paging (with pagefile) is critical for seamless gameplay and stability—especially when pushing RAM limits.
Final thoughts
Virtual memory is a powerful abstraction that allows programs to use more memory than physically available, providing isolation and protection. However, it comes with trade-offs like slower access times and complexity in managing the swap space. Understanding virtual memory is crucial for debugging and performance optimization, but it's often an OS-level concern rather than something application code needs to handle directly.
Virtual memory is solid, predictable, and does its job without much fuss. But when things go sideways, knowing how it all works can be a real lifesaver. It's more the operating system's playground than the app's, but having that low-level insight in your back pocket sets you apart. Most devs never go there. You did.
This is the final blog post about memory regions. I hope people had fun and learned something along the way, just as I did. If you want to see more blogs like this, I don't ask for anything—just stick around. Peace!!
Disclaimer
References to Unreal Engine documentation, Steam Community discussions, and Unreal Developer Forums are included for informational purposes only. I am not affiliated with Epic Games, Valve, or any related entities. The views expressed in this blog post are entirely my own and do not represent those of the referenced platforms. This is not a sponsored post.
- Streaming Virtual Texturing Streaming Virtual Texturing in Unreal Engine | Unreal Engine 5.6 Documentation | Epic Developer Community, Retrieved July 27, 2025.
- ELDEN RING General Discussions Can't play, crash on loading a saved game :: ELDEN RING General Discussions, Retrieved July 27, 2025.
- Epic Developer Community Forums UE5 needs more memory than UE4? - World Creation - Epic Developer Community Forums, Retrieved July 27, 2025.