[英]Allocating a single object larger than 2GB using new in C++ (on Windows)
[英]How can I make single object larger than 2GB using new operator?
我正在尝试使用 new 运算符使单个 object 大于 2GB。 但是如果object的大小大于0x7fffffff,分配的memory的大小就变得奇怪了。 我认为这是由编译器完成的,因为汇编代码本身使用了奇怪的 memory 分配大小。
我正在使用 Visual Stuio 2015,配置是 Release,x64。
它是VS2015的错误吗? 否则,我想知道为什么存在限制。
示例代码如下,带有汇编代码。
struct chunk1MB
{
char data[1024 * 1024];
};
class chunk1
{
chunk1MB data1[1024];
chunk1MB data2[1023];
char data[1024 * 1024 - 1];
};
class chunk2
{
chunk1MB data1[1024];
chunk1MB data2[1024];
};
auto* ptr1 = new chunk1;
00007FF668AF1044 mov ecx,7FFFFFFFh
00007FF668AF1049 call operator new (07FF668AF13E4h)
auto* ptr2 = new chunk2;
00007FF668AF104E mov rcx,0FFFFFFFF80000000h // must be 080000000h
00007FF668AF1055 mov rsi,rax
00007FF668AF1058 call operator new (07FF668AF13E4h)
我不确定如何完全解决您的问题,因为在我正确看到的任何地方都没有得到回答。
Memory 模型很棘手,直到 x64 2GB 几乎是极限。
据我所知,Windows 中的基本 memory model 不支持大量分配。
大页面支持 1GB 的 memory。
但是我想指出不同的方向:
我发现实现类似目标的 3 种方法:
VirtualAlloc
const static SIZE_T giga = 1024 * 1024 * 1024;
const static SIZE_T size = 4 * giga;
BYTE* ptr = static_cast<BYTE*>(VirtualAlloc(nullptr, (SIZE_T)size, MEM_COMMIT, PAGE_READWRITE));
VirtualFree(ptr, 0, MEM_RELEASE);
祝你好运。
使用像 clang-cl 这样未损坏的编译器,或者对最大 object 大小没有有意的有符号 32 位实现限制的编译器,以 MSVC 为准。 (这会受到 largeaddressaware 选项的影响吗?)
当前的 MSVC( Godbolt 上的 19.33 )具有相同的错误,尽管它似乎确实可以处理 2GiB static 个对象。 但不是 3GiB static 个对象; 添加另一个 1GiB 成员会在从对象的开头访问超过 2GiB 的字节时导致错误代码( Godbolt -
mov BYTE PTR chunk2 static_chunk2-1073741825, 2
- 注意负偏移量。)
GCC 针对 Linux 为 3GiB object 的情况生成了正确的代码,使用mov r64, imm64
将绝对地址获取到寄存器中,因为 RIP 相对寻址模式不可用。 (一般来说,当 some.data /.bss 地址链接在低 2GiB 之外和/或远离代码超过 2GiB 时,您需要gcc -mcmodel=medium
才能正常工作。)
MSVC 似乎已在内部将大小截断为带符号的 32 位,然后进行符号扩展。 请注意它传递给new
的 arg: mov rcx, 0FFFFFFFF80000000h
而不是mov ecx, 80000000h
(这将在写入 32 位寄存器时通过隐式零扩展设置 RCX = 0000000080000000h。)
在返回sizeof(chunk2);
作为size_t
,它工作正常,但有趣的是在源代码中将大小打印为负数。 这可能是无辜的,例如,在意识到该值适合 32 位零扩展值之后,MSVC 的 asm 打印代码可能总是将 32 位整数打印为有符号十进制,并在注释中使用无符号十六进制。
它与将 arg 传递给new
的方式明显不同; 在那种情况下,它在机器代码中使用了 64 位操作数大小,因此相同的 32 位立即数被符号扩展为 64 位,接近 SIZE_MAX 的巨大值,这当然远远大于任何可能的最大值 object x86-64 的大小。 (48 位虚拟地址空间是 size_t 的 64 位值范围的 1/65536)。
unsigned __int64 sizeof_chunk2(void) PROC ; sizeof_chunk2, COMDAT
mov eax, -2147483648 ; 80000000H
ret 0
unsigned __int64 sizeof_chunk2(void) ENDP ; sizeof_chunk2
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.