私は標準の新しい...なぜ新しいものが最初に1040の余分なバイトを割り当てるのですか?
#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;
}
を使用してメモリを割り当てるとき、アライメントの動作方法を示すために、この簡単なテストプログラムを作成していた。しかし、私はプログラムを実行したときに、私はこの奇妙な振る舞いを見つけた:
[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
ご覧のように、newによって割り当てられた2番目のブロックは、次の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
これは、通常予想される結果です。最初に走ったときに新しいことが変わったのは何故ですか?私はg ++(GCC)7.1.1 20170516を使用しています。最適化せずにコンパイルしても同じ結果になります。
これはヒープですが、起動すると(メインの前に)断片化される可能性があります。「新」はおそらくいくつかの穴を埋めるでしょう。あなたは、明確な結論に達するために、そのスタートアップコードをトレースする必要があります。 –
newによって割り当てられたメモリブロックは連続しているとは言えません。実際には、あなたが新しいものから戻ってくるアドレスはそうでないことがかなり保証されています。 –
プログラムは未定義のビヘイビアを呼び出します。■同じ配列の要素を指していないポインタは減算できません。とにかく、最初の例では、割り当て、印刷、割り当て、印刷を行い、2番目の例はprint、allocate、print、allocateを行います。これは、 'operator <<'の最初の呼び出しがバッファなど)。 –