C++ 为什么对new[]的连续调用不分配连续内存?

C++ 为什么对new[]的连续调用不分配连续内存?,c++,linux,memory,heap-memory,C++,Linux,Memory,Heap Memory,我使用的是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 <&

我使用的是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;
}
我以为操作系统会连续分配内存。那么ptr[0][0]将位于0x1195020而不是0x1195030!?操作系统在0x1195020-0x119502F、0x1195038-0x0x119504F处使用什么?

因为:

  • 每个分配内存块的开始和结束处的一些空间通常用于记账。(特别是,许多分配器发现存储前后块的大小或指向它们的指针非常有用。)

  • 内存分配器可以“四舍五入”已分配块的大小,使其更容易。例如,7个字节的分配可能会被舍入到8个字节,即使不是16或32个字节

  • 内存块可能已经在非连续位置可用。(请记住,在运行
    main()
    之前,C运行时可能已经进行了一些自己的内存分配。)

  • 分配器可能有一个布局内存的计划,如果将下一个块放在“next”地址,内存就会被破坏。(例如,它可能为特定大小的分配保留了该内存。)

  • 为什么要这样做?没有任何保证。分配的内存可能会出现在任何地方。(好的,几乎是。)不要做任何假设,只要让内存去分配程序说它会去的任何地方,你就会没事的


  • 您没有直接从操作系统分配内存。运行时管理自己的堆,而堆又是从操作系统分配的。无法保证对new()的连续调用是连续的。千万不要在代码中假设这一点。如果“我认为操作系统会连续分配内存”,那么为什么要使用ptr[r-1],而不是直接使用ptr+(偏移量0x10字节)作为ptr[r-1]?而且,每次
    malloc()
    memory或
    new[]
    数组时,运行时必须添加一些额外的字节来跟踪分配了多少内存/多少对象,因此当您稍后
    free()
    delete[]
    内存时,它知道需要清理多少内存。我建议您阅读unix系统上的动态内存分配。举个例子。引用文章:当你对一个块进行malloc时,它实际上分配的内存比你要求的要多。这个额外的内存用于存储信息,如分配块的大小、到块链中下一个空闲/使用块的链接,有时还存储一些“保护数据”无法保证第一个块的分配地址比第二个块的分配地址低,分配模式很可能取决于分配的大小(较大的块与较小的块分开分配)。您可以放心地假设,由一个
    new
    分配的空间不会与当前分配的任何其他块重叠。此外,一些分配器根据大小隔离内存块。这样做有多种原因,通常是为了尽量减少碎片。谢谢。增加了一些东西。
    0x7fff09faf018 -> 0x1195010
    0x1195010 -> 0x1195030
    0x1195030 -> 0
    0x1195034 -> 1
    0x1195018 -> 0x1195050
    0x1195050 -> 0
    0x1195054 -> 2
    0x1195058 -> 4
    0x119505c -> 6