Search code examples
c#windowsx86-64virtual-memoryinternals

May 64-bit Windows allocate virtual memory over 7FFF'FFFF'FFFF?


Context

I'm working on upgrading a .NET library to support 64-bit. That library performs various operation directly in memory of other processes on Windows. I have to choose between the two types IntPtr (max positive value 7FFF'FFFF'FFFF'FFFF) or UIntPtr (max positive value FFFF'FFFF'FFFF'FFFF) to handle my memory pointers. There is a lot of information on the Web about the two. IntPtr seems to be the de facto agreed choice, as it is CLS-compliant and most of .NET API rely on that (ref Marshal from InteropServices).

The question

I decided to open a 64-bit process and inspect the allocated memory regions, as well as the loaded modules in the process to see if it would be valuable to support unsigned pointers using UIntPtr (addresses > 7FFF'FFFF'FFFF'FFFF). As illustrated in the screenshot below, it seems the memory addresses does not load symbols, nor allocate memory over 7FFF'FFFF'FFFF. Is there a specific reason for doing so ? May Windows allocate memory regions over that value in some cases ?

Memory allocation on Cheat Engine (64-bit)


Solution

  • In Windows each process has only an address space of 8TB, therefore the upper limit for user code is 0x7FF'FFFF'FFFF

    The range of virtual addresses that is available to a process is called the virtual address space for the process. Each user-mode process has its own private virtual address space. For a 32-bit process, the virtual address space is usually the 2-gigabyte range 0x00000000 through 0x7FFFFFFF. For a 64-bit process, the virtual address space is the 8-terabyte range 0x000'00000000 through 0x7FF'FFFFFFFF. A range of virtual addresses is sometimes called a range of virtual memory.

    This diagram illustrates some of the key features of virtual address spaces.

    some of the key features of virtual address spaces

    https://learn.microsoft.com/en-us/windows-hardware/drivers/gettingstarted/virtual-address-spaces

    The upper 248TB belongs to kernel mode, summing up to 256TB of address space, which is addressed by 48 bits. That means the highest possible positive address is 247-1 = 0x7FFF'FFFF'FFFF

    In 64-bit Windows, the theoretical amount of virtual address space is 2^64 bytes (16 exabytes), but only a small portion of the 16-exabyte range is actually used. The 8-terabyte range from 0x000'00000000 through 0x7FF'FFFFFFFF is used for user space, and portions of the 248-terabyte range from 0xFFFF0800'00000000 through 0xFFFFFFFF'FFFFFFFF are used for system space.


    Update:

    As commented below, in Windows 8.1 and Windows Server 2012 R2 or later the user/kernel address space split is 128/128TB which sums up to the same 256TB space


    The significant part is 48-bit wide probably because most current x86-64 implementations use 48-bit virtual address

    The original implementation of the AMD64 architecture implemented 40-bit physical addresses and so could address up to 1 TB (240 bytes) of RAM. Current implementations of the AMD64 architecture (starting from AMD 10h microarchitecture) extend this to 48-bit physical addresses and therefore can address up to 256 TB of RAM. The architecture permits extending this to 52 bits in the future (limited by the page table entry format); this would allow addressing of up to 4 PB of RAM.

    https://en.wikipedia.org/wiki/X86-64#Architectural_features