Why does new allocate 1040 extra bytes the first time?

余生长醉 提交于 2021-01-27 16:59:37

问题


I was creating this simple test program to demonstrate the way alignment works when allocating memory using standard 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;
}

But when I executed the program I found this odd behaviour:

[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

As you can see, the second block allocated by new is not at the next 32b memory alligned address, but far away (1040 bytes away). If this is not odd enough, uncommenting the 2 std::cout lines that print out the header of the table, yields this result:

[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

This is normal expected result. What makes new behave in such an odd way at first run? I am using g++ (GCC) 7.1.1 20170516. You may compile without optimizations and result is the same.


回答1:


You'll be surprised to learn that your program does a lot more than just make a few memory allocations.

std::cout << "BLOCK " << num << ":   ";

Your program also generates formatted output to std::cout, making use of its built-in std::streambuf.

It appears rather obvious that the first output to std::cout allocates a 1024 byte buffer for the internal std::streambuf. This happens after your first new allocation, and before your second one. The buffer only needs to be allocated once, the first time it's used.

Although it goes without saying that the particulars of internal memory allocations are highly implementation-defined, this seems to be the most likely explanation in your case.




回答2:


new doesn't guarantee that memory blocks are consecutive.

Moreover, I encourage you to read about Fragmentation, which is most likely what is happening, and the system tries to fill up holes.




回答3:


Lots of things, including the stream overload of <<, use the same heap that `new' uses.

Some run times randomize allocations as a way of slowing down crackers trying buffer-overrun shenanigans.



来源:https://stackoverflow.com/questions/44749922/why-does-new-allocate-1040-extra-bytes-the-first-time

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!