我使用的是Visual Studio 2019,我注意到在调试版本中,变量之间的分配距离是如此之远。我看着Project Properties并尝试在线搜索,但找不到任何东西。我在Debug和Release模式下都运行了以下代码,分别是输出。
int main() {
int a = 3;
int b = 5;
int c = 8;
int d[5] = { 10,10,10,10,10 };
int e = 14;
std::cout << "a: " << &a
<< "\nb: " << &b
<< "\nc: " << &c
<< "\nd_start: " << &d[0]
<< "\nd_end: " << &d[4] + 1
<< "\ne: " << &e
<< std::endl;
}
如您在下面看到的,变量按照您期望的方式分配(一个接一个),中间没有浪费的内存。即使最后一个变量e
也已优化为在c和d之间插入。
// Release_x64 Build Ouput
a: 0000003893EFFC40
b: 0000003893EFFC44
c: 0000003893EFFC48
d_start: 0000003893EFFC50
d_end: 0000003893EFFC64
e: 0000003893EFFC4C // e is optimized in between c and d
下面是使我感到困惑的输出。在这里您可以看到a
和b
被分配了32个字节!因此,它们之间有28个字节的浪费/未初始化的内存。除int d[5]
以外的其他变量也会发生相同的情况。 d
在c
之后具有32个未初始化的字节,但在e
之前仅具有24个未初始化的字节。
// Debug_x64 Build Output
a: 00000086D7EFF3F4
b: 00000086D7EFF414
c: 00000086D7EFF434
d_start: 00000086D7EFF458
d_end: 00000086D7EFF46C
e: 00000086D7EFF484
我的问题是为什么会这样? MSVC为什么将这些变量分配得相距如此之远,又是什么决定了分隔它们的空间大小,使得它们对于数组而言有所不同?
调试版本的分配存储与发布版本不同。特别是,调试版本在每个存储块的开头和结尾分配一些空间,因此其分配模式有所不同。
调试分配器还在其分配的块的开头和结尾处检查存储,以查看其是否已被损坏。
存储空间是按量化的块分配的,量子的数量未指定,但大约为16或32字节。因此,如果您分配了六个元素的DWORD数组(大小= 6 * sizeof(DWORD)字节= 24字节),则分配器实际上将提供32个字节(一个32字节的量子或两个16字节的量子)。因此,如果您编写元素[6](第七个元素),则会覆盖一些“死空间”,并且不会检测到错误。但是在发行版中,量子可能是8个字节,并且将分配三个8个字节的量子,并且写入数组的[6]元素将覆盖属于下一个块的一部分存储分配器数据结构。之后,一切都是艰难的。直到程序退出,错误才会出现!您可以为任何大小的量子构造类似的“边界条件”情况。因为两个版本的分配器的量子大小都是相同的,但是分配器的调试版本会为其自身目的添加隐藏空间,因此您将在调试和释放模式下获得不同的存储分配模式。