While testing some things regarding page faults I discovered a curious difference between how new operates in Debug mode and Release mode in MSVC. Consider the following code1:
#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';
}
The code allocates a million normal memory pages on most architectures. It then physically writes to this allocated memory, so the memory really has to be "given"2 to the program - not merely "reserved" for it in some way. The curious thing is, when this actually happens. To investigate this, I stepped through the code using the Visual Studio debugger and looked at the memory usage graph in Task Manager. The results are below:
The red time point is the program being launched, the green time point/interval is the call to new char[], the blue time point/interval is the for loop.
As it turns out, in Debug mode, new both "reserves" and "gives" memory to the program. Meanwhile, in Release mode, it only "reserves" it, as the memory is "given" by the loop. I expected only the behavior present in Release mode - I thought that the memory is "given" to the program only when a page fault occurs.
Why does new behave in this way? Does this have any significant implications?
1 By the way, for some reason changing auto* pages to auto* const pages causes an Internal Compiler Error.
2 I am a bit confused regarding the correct terminology, so I used "given" and "reserved" instead.
