问题
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