为什么new第一次分配1040个额外字节?

ron*_*ldo 3 c++ heap-memory memory-alignment new-operator

我正在创建这个简单的测试程序来演示使用标准new分配内存时对齐的工作方式...

#include <iostream>
#include <iomanip>
#include <cstdint>

//
// Print a reserved block: its asked size, its start address 
//       and the size of the previous reserved block
//
void print(uint16_t num, uint16_t size_asked, uint8_t* p) {
   static uint8_t* last = nullptr;

   std::cout << "BLOCK " << num << ":   ";
   std::cout << std::setfill('0') << std::setw(2) << size_asked << "b, "; 
   std::cout << std::hex << (void*)p;
   if (last != nullptr) {
      std::cout << ", " << std::dec << (uint32_t)(p - last) << "b";
   }
   std::cout << "\n";
   last = p;
}

int main(void) {
   // Sizes of the blocks to be reserved and pointers
   uint16_t s[8] = { 8, 8, 16, 16, 4, 4, 6, 6 };
   uint8_t* p[8];

   // Reserve some consecutive memory blocks and print
   // pointers (start) and their real sizes
//   std::cout << "          size   start    prev.size\n";
//   std::cout << "-----------------------------------\n";
   for(uint16_t i = 0; i < 8; ++i) {
      p[i] = new uint8_t[s[i]];
      print(i, s[i], p[i]);
   }

   return 0;
}
Run Code Online (Sandbox Code Playgroud)

但是当我执行程序时,我发现了这种奇怪的行为:

[memtest]$ g++ -O2 mem.cpp -o mem
[memtest]$ ./mem 
BLOCK 0:   08b, 0xa0ec20
BLOCK 1:   08b, 0xa0f050, 1072b
BLOCK 2:   16b, 0xa0f070, 32b
BLOCK 3:   16b, 0xa0f090, 32b
BLOCK 4:   04b, 0xa0f0b0, 32b
BLOCK 5:   04b, 0xa0f0d0, 32b
BLOCK 6:   06b, 0xa0f0f0, 32b
BLOCK 7:   06b, 0xa0f110, 32b
Run Code Online (Sandbox Code Playgroud)

如您所见,new分配的第二个块不是在下一个32b内存的对齐地址,而是远在(1040个字节以外).如果这不够奇怪,取消注释打印出表头的2 std :: cout行会产生以下结果:

[memtest]$ g++ -O2 mem.cpp -o mem
[memtest]$ ./mem 
          size   start    prev.size
-----------------------------------
BLOCK 0:   08b, 0x1f47030
BLOCK 1:   08b, 0x1f47050, 32b
BLOCK 2:   16b, 0x1f47070, 32b
BLOCK 3:   16b, 0x1f47090, 32b
BLOCK 4:   04b, 0x1f470b0, 32b
BLOCK 5:   04b, 0x1f470d0, 32b
BLOCK 6:   06b, 0x1f470f0, 32b
BLOCK 7:   06b, 0x1f47110, 32b
Run Code Online (Sandbox Code Playgroud)

这是正常的预期结果.是什么让新手在首次运行中以如此奇怪的方式表现?我正在使用g ++(GCC)7.1.1 20170516.您可以编译而不进行优化,结果是相同的.

Sam*_*hik 6

你会惊讶地发现你的程序不仅仅是做一些内存分配.

std::cout << "BLOCK " << num << ":   ";
Run Code Online (Sandbox Code Playgroud)

您的程序还会生成格式化输出std::cout,并使用其内置功能std::streambuf.

很明显,第一个输出std::cout为内部分配1024字节缓冲区std::streambuf.这是在您第一次new分配之后和第二次分配之前发生的.缓冲区只需要在第一次使用时分配一次.

虽然不言而喻,内部存储器分配的细节是高度实现定义的,但这似乎是您案例中最可能的解释.