为什么 new 第一次分配 1040 个额外的字节?
Why does new allocate 1040 extra bytes the first time?
我正在创建这个简单的测试程序,以演示使用标准新内存分配内存时的对齐方式...
#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.sizen";
// 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 分配的第二个块不在下一个 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
这是正常的预期结果。是什么让 new 在第一次运行时表现得如此奇怪?我正在使用 g++ (GCC) 7.1.1 20170516。您可以在不进行优化的情况下进行编译,结果是相同的。
你会惊讶地发现,你的程序所做的不仅仅是进行一些内存分配。
std::cout << "BLOCK " << num << ": ";
您的程序还可以生成格式化的输出以std::cout
,利用其内置std::streambuf
。
很明显,std::cout
的第一个输出为内部std::streambuf
分配了一个 1024 字节的缓冲区。这发生在您第一次new
分配之后,第二次分配之前。缓冲区只需分配一次,即第一次使用
。尽管不言而喻,内部存储器分配的细节是高度实现定义的,但这似乎是您案例中最有可能的解释。
new
不能保证内存块是连续的。
此外,我鼓励您阅读有关碎片的信息,这很可能是正在发生的事情,并且系统试图填补漏洞。
很多东西,包括<<
的流重载,使用与"new"相同的堆。
一些运行时间将分配随机化,作为减缓饼干尝试缓冲区溢出恶作剧的一种方式。
相关文章:
- 从不同线程使用int64的不同字节安全吗
- 将Integer转换为4字节的unsined字符矢量(按大端字节顺序)
- 在UNIX系统中使用DIR查找文件的字节大小
- 如何使用Crypto++并为RSA返回可打印的字节/字符数组
- 如果"new int"返回"int*",那么为什么"new int[n]"不返回"int**"?
- std::当在256字节边界上写入整数时,流的奇怪行为
- 有没有一种方法可以使用placement new将堆叠对象分配给分配的内存
- 重载运算符new[]的行为取决于析构函数
- 当比特(而不是字节)的顺序至关重要时的持久性
- 从文件中读取多个字节,并将它们存储在C++中进行比较
- 如何在文件中查找字节序列
- luaL_dofile在已知良好的字节码上失败,可以使用未编译的版本
- 如何使用 new in C++ 分配字节数内存
- 为什么 new 第一次分配 1040 个额外的字节?
- 运算符new[]不接收额外的字节
- new分配了多少字节
- new[] 一个包含构造函数的字节对象数组没有错,对吧?
- C++强制 new[] 不分配 4 个额外的字节
- 通过new[]分配n个字节,并用任何类型填充它
- 计算"new"和"delete"字节