使用C ++处理内存映射

时间:2018-03-31 06:50:15

标签: memory memory-management new-operator heap-memory

#include <iostream>

int main(int argc, char** argv) {
  int* heap_var = new int[1];
  /*
   * Page size 4KB == 4*1024 == 4096
   */
  heap_var[1025] = 1;
  std::cout << heap_var[1025] << std::endl;
  return 0;
}

// Output: 1

在上面的代码中,我在堆中分配了4个字节的空间。现在,当OS将虚拟内存映射到页面中的系统内存(每个4KB)时,我的虚拟mems堆中的4KB块将被映射到系统内存。为了测试,我决定尝试访问我分配的页面/堆块中的其他地址并且它有效,但是我不应该被允许从一开始就访问超过4096个字节(这意味着索引1025作为一个int变量是4字节)。

我很困惑为什么我能够从堆块的开头访问4 * 1025字节(超过已分配页面的大小)而不会出现seg错误。

感谢。

1 个答案:

答案 0 :(得分:2)

平台分配器可能分配的页面大小远远超过页面大小,因为它计划使用该内存“桶”进行其他分配,或者可能在那里保留一些内部状态,很可能在发布版本中存在远远超过只是一个页面大小的虚拟内存块。你也不知道那个特定页面在哪里分配了内存(你可以通过掩盖一些比特来找到)并且没有提到平台/拱门(我假设x86_64)没有告诉这个页面甚至是4kb,它可能是2MB“巨大”的页面或类似的东西。

但是,通过访问外部数组边界,您将触发未定义的行为,如果在写入情况下发生读取或数据损坏,则会发生崩溃。

请勿使用您不拥有的内存。

我还应该提一下,这可能与C ++无关,因为new[]运算符通常只是在核心平台库的幕后调用malloc / calloc({{1在OSX或libSystemglibc或Linux上的任何其他内容,甚至是拦截分配器)。您遇到的段错误通常来自堆块周围的保护页面,或者在没有保护页面的情况下使用未映射的内存。

注意:请勿在家中尝试:有些情况下,您可能会故意触发一般会被视为未定义行为的内容,但在该特定平台上可能确切知道那里有什么(一个很好的例子就是在Linux上滥用musl opaque以获得pthread_t而没有额外系统调用的开销,但你必须确保使用正确的libc,右边构建该libc的类型,该libc的正确版本,使用它构建的正确编译器等)。