为啥连续调用 new[] 不分配连续内存?
Posted
技术标签:
【中文标题】为啥连续调用 new[] 不分配连续内存?【英文标题】:Why do successive calls to new[] not allocate contiguous memory?为什么连续调用 new[] 不分配连续内存? 【发布时间】:2014-10-29 21:50:44 【问题描述】:我使用的是 Ubuntu 14.04 64 位。这是我的 C++ 代码,看看内存是如何使用的。
int main()
int **ptr;
ptr = new int* [2];
cout << &ptr << " -> " << ptr << endl;
for (int r = 1; r <= 2; r++)
ptr[r-1] = new int [2 * r];
cout << &ptr[r-1] << " -> " << ptr[r-1] << endl;
for (int c = 0; c < 2 * r; c++)
ptr[r-1][c] = r * c;
cout << &ptr[r-1][c] << " -> " << ptr[r-1][c] << endl;
return 0;
这是我的输出:
0x7fff09faf018 -> 0x1195010
0x1195010 -> 0x1195030
0x1195030 -> 0
0x1195034 -> 1
0x1195018 -> 0x1195050
0x1195050 -> 0
0x1195054 -> 2
0x1195058 -> 4
0x119505c -> 6
我预计操作系统会连续分配内存。所以 ptr[0][0] 会在 0x1195020 而不是 0x1195030!? OS 在 0x1195020 - 0x119502F, 0x1195038 - 0x0x119504F 处使用什么?
【问题讨论】:
您不是直接从操作系统分配内存。运行时管理自己的堆,而堆又是从操作系统分配的。不能保证对 new() 的连续调用是连续的。永远不要在你的代码中假设这一点。 如果“我认为操作系统会连续分配内存。”,那么为什么要使用 ptr[r-1] 而不仅仅是直接 ptr +(偏移量 0x10 字节)作为 ptr[r-1] ? 另外,每次你malloc()
内存或 new[]
数组时,运行时都必须添加一些额外的字节来跟踪分配了多少内存/多少对象,所以当你稍后free()
或 delete[]
它知道要清理多少内存。
我建议您阅读有关 unix 系统上的动态内存分配的信息。以article 为例。引用文章:当你 malloc 一个块时,它实际上分配的内存比你要求的多一点。这个额外的内存用于存储信息,例如分配块的大小,以及到块链中下一个空闲/使用块的链接,有时还有一些“保护数据”
不能保证第一个块将被分配到比第二个块更低的地址——分配模式很可能取决于分配的大小(较大的块与较小的块分开分配块)。您可以放心地假设一个new
分配的空间不会与任何其他当前分配的块重叠。
【参考方案1】:
因为:
每个分配的内存块的开头和结尾的一些空间通常用于簿记。 (特别是,许多分配器发现在周围存储前后块的大小或指向它们的指针很有用。)
内存分配器可能会“向上取整”已分配块的大小,以使事情变得更容易。例如,分配的 7 个字节可能会四舍五入到 8 个字节,即使不是 16 或 32 个字节。
内存块可能已经在不连续的位置可用。 (请记住,在 main()
运行之前,C 运行时可能已经自行分配了一些内存。)
分配器可能有一个布局内存的计划,如果将下一个块放在“下一个”地址,这将被破坏。 (例如,它可能已经为特定大小的分配保留了该内存。)
为什么要这样做?没有任何保证。分配的内存可能会在任何地方结束。 (嗯,差不多。)不要做任何假设,只要让内存去分配器说它去的地方,你会没事的。
【讨论】:
另外,一些分配器根据大小分离内存块。这样做有多种原因,通常是为了尽量减少碎片。 谢谢。为此添加了一些东西。以上是关于为啥连续调用 new[] 不分配连续内存?的主要内容,如果未能解决你的问题,请参考以下文章