Dive into Windows internals. This guide demystifies how processes work and how memory is managed. Explore virtual address space, VADs, page states (free, reserved, committed), and the crucial split between user and kernel space. A clear look at the OS core.

While this blog aims to make these ideas accessible, I highly recommend reading the original "Windows Kernel Programming" book for more information.
A process in Windows is not what executes the code it is a container that manages and holds everything necessary for execution. The actual execution happens inside threads, which run inside the process. The process itself is more like an environment that provides resources and context for those threads.
a process includes the following important components:
a process is uniquely identified using Process ID, which remain unique as long as kernel process object exits.Once it’s destroyed, the same ID may be reused for new processes. It’s important to realize that the executable file itself is not a unique identifier of a process
Every process in Windows gets its own private virtual address space, which means the addresses it sees are isolated from all other processes. This ensures that one process cannot directly read or modify another process’s memory a fundamental part of process protection and stability.
when a process start it's virtual address space is mostly empty, with only a few component mapped:
NTDLL.dll a key user-mode library providing system call interfaceskernel32.dllwhen the process runs, more regions are added like heap memory, more stack space for each thread. more loaded DLLs, memory-mapped files, and so on. these regions are managed via virtual address space or VADs which record parts of the space that are reserved, commuted, and what protection they have.
The layout and total size of the virtual address space depend on the process and operating system architecture:
For a standard 32-bit process running on 32-bit Windows, the 4 GB of total virtual address space is split evenly:
For a 64-bit process on 64-bit Windows, the address space is astronomically larger, providing a massive canvas for both user and kernel code:
Every process in Windows operates within its own private virtual address space, a vast and seemingly empty landscape of memory addresses. But how does the operating system keep track of which parts of this space are being used, what they're used for, and what rules apply to them?
This is where the Virtual Address Descriptor (VAD) comes in.
A VAD is a kernel data structure that acts like a blueprint for a specific, continuous range of virtual addresses within a process. Think of it as a deed to a plot of land in the process's memory map. Instead of just one VAD, the Windows Memory Manager maintains a whole collection of them for each process, organized in a highly efficient, self-balancing tree structure (similar to an AVL tree). This allows the kernel to quickly find, add, or remove memory regions.
When a thread tries to access a virtual address, the kernel swiftly searches the VAD tree to answer critical questions:
Each VAD node stores essential information to manage its memory block, including:
When a 64-bit process starts, its virtual address space is populated with a few key components:
0x0000000000000000 to 0x000000000000FFFF: This initial 64 KB region is reserved and made inaccessible to catch NULL pointer errors.0x0000000000010000: The main executable (.exe) is mapped here.0x00007FF800000000: The core system library, ntdll.dll, is mapped into a high address.0x00007FFA00000000: Other essential DLLs, like kernel32.dll, are also mapped nearby.As the process allocates memory (malloc, VirtualAlloc, etc.), new VADs appear in this virtual space. However, physical RAM is not necessarily used until those regions are accessed virtual memory allows on-demand commitment of page
memory address has three characteristics we need to understand:
When you refer to address 0x20000, that number alone doesn’t tell you what memory is there; you must also know which process you’re in. Because each process maps its own virtual addresses differently, the same virtual address can map to different physical memory or none at all in different processes.
When your code tries to read or write memory via a virtual address, the CPU/OS perform several steps:
This mechanism lets programs act as if they have a large, continuous memory space, without requiring all of it to be physically in RAM at once.
in Windows, memory is not managed byte by byte, but in fixed-size blocks known as pages. The page is the fundamental unit of memory management. All attributes, such as whether a memory region can be read from, written to, or executed, are applied at this page level. This means an entire page shares the same protection status; you cannot, for instance, make half a page readable and the other half read-only. The standard page size is determined by the CPU architecture, which for most modern systems is 4 KB. Consequently, all memory operations performed by the OS, from allocating memory to changing its protection, are done in multiples of this page size.
To optimize performance for applications that handle large datasets, Windows also supports large pages (typically 2 MB) and huge pages (1 GB). By mapping a vast memory region with a single translation entry instead of hundreds, these larger pages significantly speed up memory access and reduce the overhead on the CPU's address translation cache (the TLB).
However, this performance boost comes with notable trade-offs. Large and huge pages require a single, unbroken block of contiguous physical memory, which can be difficult to allocate if RAM is fragmented. Furthermore, they are non-pageable, meaning they are locked into physical RAM and can never be swapped out to disk, which can put pressure on system memory. Finally, they support a more limited set of protection flags compared to standard 4 KB pages.
each page in virtual memory can be in one of the three state
malloc()` or `VirtualAlloc(..., MEM_COMMIT)`, Windows commits pages — they can now store data or code.VirtualAlloc(..., MEM_RESERVE) so that it has a continuous range of virtual addresses, but commit smaller portions (4 KB or more) later when actually needed. This is common in thread stack allocation and memory pools.The lower part of the address space is for user-mode processes use.and the upper part is for the operating system and kernel-mode code.
in 32-bit Windows, the total address space is 4 GB (2³² = 4 GB). By default, the lower 2 GB (0x00000000–0x7FFFFFFF) are for user-mode processes, and the upper 2 GB (0x80000000–0xFFFFFFFF) are for the operating system.
On 64-bit Windows, the address space is vastly larger.In Windows 8 and Server 2012 (and earlier), the OS uses the upper 8 TB for kernel-mode space. From Windows 8.1 and Server 2012 R2 onward, the OS reserves the upper 128 TB for kernel-mode space.
Published Oct 27, 2025