jan*_*b04 2 c++ memory memory-management visual-c++ page-fault
new在测试有关页面错误的一些内容时,我发现MSVC 中调试模式和发布模式下的操作方式存在一个奇怪的差异。考虑以下代码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';
}
Run Code Online (Sandbox Code Playgroud)
该代码在大多数体系结构上分配一百万个普通内存页。然后它会物理地写入这个分配的内存,因此内存实际上必须“给予” 2给程序 - 而不仅仅是以某种方式为其“保留”。奇怪的是,当这真的发生时。为了调查这个问题,我使用 Visual Studio 调试器单步调试了代码,并查看了任务管理器中的内存使用情况图。结果如下:
红色时间点是正在启动的程序,绿色时间点/间隔是对 的调用new char[],蓝色时间点/间隔是循环for。
事实证明,在调试模式下,new“保留”和“提供”内存给程序。同时,在释放模式下,它仅“保留”它,因为内存是由循环“给出”的。我只期望释放模式中存在的行为 - 我认为仅当发生页面错误时才会将内存“提供”给程序。
为什么会有new这样的行为?这有什么重大影响吗?
1顺便说一句,由于某种原因,更改auto* pages为auto* const pages导致内部编译器错误。
2我对正确的术语有点困惑,所以我用“给定”和“保留”代替。
要了解发生了什么,您需要了解两件事:
第 1 点和第 2 点的组合意味着调试版本new获取内存并立即通过写入未初始化内存检测模式来访问它,并强制系统在绿色区域中查找并移交真实内存。作为一个额外的好处,如果计算机确实耗尽了物理存储空间,程序很可能会在这里崩溃,而不是在未来某个看似随机的点无法满足请求时崩溃。
的发布版本new没有执行第 1 点,因此物理内存获取会按照第 2 点延迟。new快速退出绿色区域,无需任何物理内存。如果所请求的部分或全部内存从未被使用过,则计算机将因不必执行满足请求的工作而受益。该程序确实使用了所请求的存储空间for,因此系统被迫在蓝色区域中查找并提供物理内存。