Winapi 为什么对于大于0x6FFFFFFFF的lpAddress,VirtualAlloc会失败

Winapi 为什么对于大于0x6FFFFFFFF的lpAddress,VirtualAlloc会失败,winapi,64-bit,Winapi,64 Bit,我想尝试通过使用VirtualAlloc将尽可能接近64位的地址映射到有效内存中,来了解在64位C程序中可以指向的“远”的限制 我设法找到了0x6ffffffffffff,这是一个42位的地址,但上面的任何数字都会导致分配失败,错误代码为0x57(参数不正确) 这是我的代码: #include <Windows.h> #include <stdio.h> int main(int argc, char **argv) { LPVOID mem; WCHA

我想尝试通过使用VirtualAlloc将尽可能接近64位的地址映射到有效内存中,来了解在64位C程序中可以指向的“远”的限制

我设法找到了
0x6ffffffffffff
,这是一个42位的地址,但上面的任何数字都会导致分配失败,错误代码为0x57(参数不正确)

这是我的代码:

#include <Windows.h>
#include <stdio.h>

int main(int argc, char **argv)
{
    LPVOID mem;
    WCHAR message[] = L"Hello, World!";

    mem = VirtualAlloc (        
        (LPVOID)0x00006ffffffffff,
        4096,
        MEM_RESERVE | MEM_COMMIT,
        PAGE_READWRITE
    );

    if (mem == 0) {
        wprintf(L"%x.\n", GetLastError());
        system("pause");
        exit(-1);
    }

    memcpy(mem, message, sizeof(message));

    wprintf(L"[%llx] -> %ls\n", mem, mem);

    system("pause");

    return 0;
}
#包括
#包括
int main(int argc,字符**argv)
{
LPVOID-mem;
WCHAR消息[]=L“你好,世界!”;
mem=虚拟现实(
(LPVOID)0x00006FFFFFFFF,
4096,
保留|承诺|,
页面\读写
);
if(mem==0){
wprintf(L“%x.\n”,GetLastError());
系统(“暂停”);
出口(-1);
}
memcpy(mem,message,sizeof(message));
wprintf(L“[%llx]->%ls\n”,mem,mem);
系统(“暂停”);
返回0;
}

为什么我不能在上面使用VirtualAlloc
0x6ffffffffff

原因是您请求的地址超出了可用范围。虽然理论上有64位的可用地址范围,但实际上并非所有的可用地址范围都适用于用户模式应用程序。通过调用
GetSystemInfo
并检查
lpMinimumApplicationAddress
lpmaximuapplicationaddress
的值,可以找到允许的范围。如果试图保留此范围之外的地址,则调用
VirtualAlloc
将失败,错误代码设置为
error\u INVALID\u参数


请注意,这些最小值和最大值并不精确。当接近极限时,您将开始观察
ERROR\u INVALID\u参数。

您当前的CPU只有48位地址空间,至少在其他系统(不确定Windows)上,一半的地址空间通常保留给内核。内核难道没有自己的地址空间可供使用吗?在我的进程的地址空间中,这些字节是为特定目的保留的吗?我在考虑堆栈,但我不确定如何测试它。不确定windows,但对于Linux,堆栈从高地址开始,然后向下扩展。您试图保留的页面可能已被锁定,用作堆栈页面或类似页面。这在某种程度上与错误代码冲突,但如果在alloc函数调用中硬编码42位限制,则可能仍然是正确的。请尝试调用
GetSystemInfo
,并查看
lpMaximumApplicationAddress
@Dmitry内核可能有自己的地址空间,但在用户区和内核之间传递数据会非常痛苦,因此,这通常是不做的。只为内核保留一部分地址空间要容易得多(就像我提到的,我不知道Windows是这么做的,但其他人都这么做,因为这样更简单、更快)。如果您想知道为什么它只有48个,那是因为没有x86 CPU实现更多。我的lpMaximumApplicationAddress是
0x7ffffffffff
这是
0xffff0000
低于最大值。似乎有点奇怪。如果它们将被保留,它还会给出错误0x57吗?好的,因此解释肯定是地址已被保留。如果地址已被保留,错误将是487-
错误\u无效\u地址
。我猜某些特定窗口上存在一些bug或钩子,因为在win7+(不检查vista)上分配的地址最多为
000007ffffffff
,而从win8so开始分配的地址最多为
00007ffffffff
,所以如果您试图保留已保留的地址,则必须使用语句2,然后对VirtualAlloc的调用将失败,错误代码设置为
error\u INVALID\u ADDRESS
当您接近极限时,您将开始观察error\u INVALID\u参数
-现在(最多赢10次)正好在64K上。当
lpAddress
lpAddress+dwSize
>
MM\u最高值\u VAD\u地址时,exist和VirtualAlloc返回
ERROR\u INVALID\u参数
-