簡體   English   中英

如何使用新運算符使單個 object 大於 2GB?

[英]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 種方法:

  1. 顯而易見的答案 - 將您的分配分成更小的塊 - 它更有效 memory 。
  2. 使用不同類型的交換,您可以將 memory 寫入文件。
  3. 使用virtual memory,不確定對你有沒有幫助,使用windows api 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

這看起來像是一個編譯器錯誤或有意的實施限制; 如果未知,請向 Microsoft 報告。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM