我在负载测试期间检测到我的程序中存在错误并进行了调查。乍一看,我以为我的代码有错误。但是,它使用的数据量较小,并且按预期调试逐步执行。所以我将我的代码缩减为以下示例。没有处理,只有分配:
void main(void) {
const signed int n = 100000000; /* high on purpose */
signed int k;
char **Buffer = NULL;
Buffer = (char**) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, n * sizeof(char*));
if (!Buffer) {
printf("Fail to allocate the big buffer\n");
return;
}
for (k = 0; k < n; ++k) {
Buffer[k] = (char*) HeapAlloc(GetProcessHeap(), 0, 3 * sizeof(char)); /* using malloc also causes failure */
if (Buffer[k] == NULL) {
printf("Out of memory on buffer no. %d\n", k);
/* break; */
}
}
/* break point here */
for (--k; k >= 0; --k)
if (Buffer[k])
HeapFree(GetProcessHeap(), 0, Buffer[k]);
HeapFree(GetProcessHeap(), 0, Buffer);
}
计算机有 12Go RAM,没有页面文件(交换)。当我运行这段代码时,内存消耗如预期的那样增加到我没有更多可用内存的程度。分配在最后往往会变慢,然后开始失败。之后,我的程序和其他应用程序崩溃,包括 Windows(7 SP1 64 位)和我的调试器(Visual Studio 2013)的位。 我不能使用 break 语句,因为代码要放在 OpenMP block 中(我将使用标志)。不过,我进行了测试,它并没有改变任何东西。
知道为什么它会导致一切崩溃吗?
这是我的猜测。当我分配少量内存的大量实例时,我可能会遇到剩余可用页面为零(或非常接近)的情况。所以其他应用程序也不能分配内存,即使是少量的。他们可能要么不能很好地处理内存不足,要么绝对需要它并崩溃。 Visual Studio 或 Windows 可能会担心并在崩溃时崩溃我的应用程序。一旦我得到一个带有 PAGE_FAULT_IN_NONPAGED_AREA 错误的 BSD。
我对导致崩溃的原因的猜测是正确的还是我遗漏了什么?是我的代码有误还是存在我不知道的已知错误?
我的真实代码接收一个输入、处理它并存储它。循环输入的是用户。这个示例告诉我,检测分配失败不是正确的方法,因为已经太晚了。你对如何防止这种情况有什么想法吗?在每次分配之前检查可用内存量肯定会破坏性能。
此外,操作系统不应该保留空闲内存以防止单个程序消耗所有内存吗?
这似乎是教科书般的案例。但是,我找不到导致该错误的任何类似代码。
最佳答案
内存管理行为因操作系统而异。我不熟悉 Windows 7 操作系统中实现的内存管理单元,但是当资源匮乏时,您几乎无能为力(从内核的角度来看)。通常,操作系统更愿意终止请求大量资源的进程,这可能就是您的情况。
你已经指出了一个“保留区域”的行为,但这不会解决问题,即使它被实现了,因为如果区域被保留,你仍然需要决定哪些进程将使用它,以及哪些进程不会,导致不允许使用它的进程饿死(并停止)。当然,内核应该足够清晰,为自己的例程保留内存,以防止自身崩溃(所以我不知道为什么 Windows 内核会崩溃,但正如我所指出的,我不熟悉它的实现).
我建议你从操作系统的角度阅读一些关于内存管理(特别是关于windows内存管理)的论文或书籍。这将为您提供一些进一步研究的线索。
希望这对您有所帮助。
关于c - 分配所有内存使我的系统崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23460214/