Why is the new one allocating 1040 extra bytes the first time?

I was creating this simple test program to demonstrate how 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 strange behavior:

[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 with the new one is not in the next 32-bit memory address, but far away (1040 bytes). If it's not that strange, uncommenting lines 2 of std :: cout that print out the table header, you get 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 the normal expected result. What makes the new one behave in such a weird way on first launch? I am using g ++ (GCC) 7.1.1 20170516. You can compile without optimization and the result is the same.

+3


source to share


3 answers


You will be surprised to learn that your program does much more than just allocate multiple memory allocations.

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

      

Your program also generates formatted output std::cout

using the inline std::streambuf

.



It looks like the first output is not std::cout

allocating a 1024 byte buffer for internal std::streambuf

. This happens after your first selection new

and before your second. The buffer only needs to be allocated once, the first time it is used.

While it goes without saying that the internal memory allocation details are highly implemented, this seems to be the most likely explanation in your case.

+6


source


new

does not guarantee that blocks of memory are sequential.



Also, I recommend that you read the Fragmentation , which is most likely happening and the system is trying to fill the holes.

+1


source


Lots of things, including stream overloading <<

, use the same heap as "new".

Some time series randomize distributions as a way to slow down crackers trying to intercept spooled files.

0


source







All Articles