gpt4 book ai didi

c++ - 在 MSVC 中,Operator new 在 Debug 模式下的行为与 Release 模式下的行为不同

转载 作者:行者123 更新时间:2023-12-05 09:29:05 26 4
gpt4 key购买 nike

在测试有关页面错误的一些事情时,我发现 new 在 MSVC 的 Debug模式和 Release模式下的运行方式之间存在奇怪的差异。考虑以下代码1:

#include <array>

constexpr size_t PAGE_SIZE = 4096;

int main()
{
const size_t count = 1000000;
char* const mem = new char[PAGE_SIZE * count];

// page align the pointer, c-style casts used for brevity
auto* pages = (std::array<char, PAGE_SIZE>*)((size_t)mem - (size_t)mem % PAGE_SIZE + PAGE_SIZE);

for (int i = 0; i < count; ++i)
pages[i][0] = 'a';
}

代码分配一百万正常内存pages在大多数架构上。然后它物理地写入这个分配的内存,所以内存真的必须“给”2 给程序——而不仅仅是以某种方式“保留”给它。奇怪的是,当这真的发生时。为了对此进行调查,我使用 Visual Studio 调试器逐句检查了代码,并查看了任务管理器中的内存使用情况图。结果如下:

Measurement results

红色时间点是正在启动的程序,绿色时间点/区间是调用new char[],蓝色时间点/区间是for 循环。

事实证明,在 Debug模式下,new 为程序“保留”和“提供”内存。同时,在 Release模式下,它只“保留”它,因为内存是由循环“提供”的。我只期望 Release模式下出现的行为 - 我认为只有在发生页面错误时才会将内存“分配”给程序。

为什么 new 会这样?这有什么重要意义吗?


1 顺便说一句,由于某种原因,将 auto* pages 更改为 auto* const pages 会导致内部编译器错误。

2 我对正确的术语有点困惑,所以我使用了“given”和“reserved”。

最佳答案

要了解发生了什么,您需要了解两件事:

  1. 调试版本为您做了很多很酷的事情来帮助您找到错误。一种方法是将一个已知值写入程序内存,这样您就可以更轻松地识别出您弄乱了未初始化的存储空间。
  2. CPU 中的现代内存管理系统很复杂,但它们都倾向于做的一件事是尽可能少,直到它们不得不这样做。当程序请求存储时,底层系统会检查是否有足够的虚拟寻址空间,然后几乎总是允许请求而不填充它。没有找到物理内存并分配给虚拟内存。访问内存时,将找到并分配物理内存,否则程序将因内存不可用而失败。

结合点1和点2意味着调试版本的new通过写入未初始化内存检测模式获取内存并立即访问它并强制系统在中找到并移交真实内存绿色区域。作为一个额外的好处,如果计算机确实用完了物理存储空间,程序可能会在这里崩溃,而不是在未来无法满足请求时的某个看似随机的点。

new 的发布版本没有做第 1 点,所以物理内存获取按照第 2 点延迟。new 快速退出绿色区域,没有任何物理内存。如果从未使用过部分或全部请求的内存,则计算机无需执行满足请求的工作即可获利。该程序确实在 for 循环中使用了请求的存储空间,因此系统被迫在蓝色区域中查找并提供物理内存。

关于c++ - 在 MSVC 中,Operator new 在 Debug 模式下的行为与 Release 模式下的行为不同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/70840151/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com