![](/img/trans.png)
[英]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.