Virtual Memory
Virtual memory is a way of providing every running process with the same liner memory address space, all processes can allocate memory from the same virtual location as they are completely isolated from each other, an operating systems memory manager provides a translation from the processes virtual address space into the physical memory it occupies.
On a 32-bit Windows operating system, every process is allocated a 4Gb virtual address space. On a standard system configuration this is split into 2 equal parts.
0x00000000 – 0x7FFFFFF – 2Gb of user mode virtual address space applications can allocate for their own use.
0x80000000 – 0xFFFFFFFF – 2Gb of kernel mode virtual address space which contains the operating system image, device drivers, page frame umber (PFN) database, system page table entries (PTE’s), paged and nonpaged memory pools.
The user mode portion of the address space is unique to every running process giving every process up to 2Gb of memory to consume.
The kernel mode portion is shared and is mapped into every process. It’s for this reason people refer to the 32-bit 2Gb kernel memory limit as one of the main resource limitations in a Terminal Server / Citrix environment. Hundreds of users can be running thousands of processes all with their own 2Gb user mode address space, but all sharing the same 2Gb kernel mode space.
The /3GB boot.ini switch can alter the split giving each processes a 3Gb user mode virtual address space, limiting the shared kernel mode address space to 1Gb.
With 64-Bit Windows, virtual address space sizes have increased significantly. The current size of the user mode address space is 8192GB and system PTE, system cache, paged pool and nonpaged pool all having a 128GB allocation in kernel mode.
What is Fragmentation?
Fragmentation of any virtual address space occurs over time as more and more blocks of memory are allocated and freed. Memory allocations can only succeed in contiguous blocks of memory, for example if a 2mb allocation was requested it would be allocated from a complete contiguous 2mb block of virtual memory and not from a 1mb block at the start of the pool and a 1mb block at the end.
When a virtual address space is initially created all of it is available for allocation and requests are simply satisfied from the next available virtual address.

(Fig 1 – 3 memory allocations consuming 80mb of a 160mb virtual address space)
Fragmentation only begins to occur when memory allocations are freed.

(Fig 2 – 2 more blocks have been allocated and a 3rd 20mb block freed)
Fig 2 shows a single fragmentation of 20Mb. Blocks of free space in between allocations can be reused providing the requested allocation is small enough to fit. Figure 3 below shows the 20mb fragmentation reused by 2 additional 10mb allocations.

(Fig 3 – 2 additional 10mb allocations have reused the 20mb fragmentation)
So when does fragmentation become a problem?

(Fig 4 – 7 allocations consuming 80mb of the 160mb virtual address space)
When an address space becomes very fragmented it can cause larger memory allocations to fail as there is not enough contiguous space to satisfy the request. Take Figure 4 as an example, as the address space is fairly fragmented the largest single allocation possible is 30mb, anything larger would fail even though there is a total of 80mb available for allocation in the address space. 8 allocations of 10mb would succeed where as 2 allocations of 40mb would fail.
Is this a problem?
Typically a user would never have problems with fragmentation, in user mode a process would need to allocate close to the 2Gb limit (x86), before experiencing any problems, it also depends on how an application developer has written their application. For example a 10kb buffer is required to perform an operation which will be repeated several thousand times. Does the developer allocate the 10kb buffer once when the program starts, or does it get allocated and freed each time it is required. The more memory allocations an application performs the more fragmented the address space can become.
Memory allocation failures due to fragmentation are most often seen in the kernel mode address space specifically in the paged and nonpaged system memory pools. As these 2 pools are used by almost every component in all operations performed in kernel mode they can become exhausted and very fragmented especially under workloads such as Terminal Services. I have seen examples of users failing to connect to a Citrix XenApp server because the ICA remote display driver could not allocate 400Kb of paged pool memory even though there was more than 30mb available at the time.
What can be done?
Today there is not a lot that can be done to resolve this. When memory allocations succeed a pointer to the start of the memory block is returned, if Microsoft were to implement background memory defragmentation routines, the original returned memory pointers would change as a result. There are no notification methods available in Windows to signal processes that memory allocations have moved. Windows applications assume the address given after a successful memory allocation is valid and will not change until it is freed.