Windows 由于 64 位进程的过多内存分配而冻结

Windows freezes due to excessive memory allocation of 64-bit process

当我在 Windows(版本 7 及更高版本)上 运行 一个 64 位程序并且该程序试图分配太多内存(接近 100% 的物理内存)时,系统会崩溃停下来。如果我没有及时发现它并终止有问题的进程,系统将变得无响应并且需要硬重启。显然程序不应该尝试分配这么多内存,但是错误可能会发生,我想保护其他 运行ning 进程免受我正在处理的代码中任何此类错误的影响 testing/debugging. (这在 32 位中不是什么大问题,因为逻辑内存限制为系统范围的内存阻塞提供了安全网。)

所以我有两个问题:

这是导致我的计算机死机的示例代码。它是在 x86_amd64 配置中使用 Visual Studio 10.0 编译的,我 运行 它是在 Windows 8.1 下具有 16 GB RAM 的笔记本电脑上编译的。它尝试分配 32 GB 的内存。 运行 风险自负。

int main(void)
{
    const static int csNumArrays=10, csArraySize=800000000;
    int i, j, **p;

    p=new int*[csNumArrays];
    for (i=0; i<csNumArrays; ++i)
    {
        p[i]=new int[csArraySize];
        for (j=0; j<csArraySize; ++j)
            p[i][j]=j;
    }
    return 0;
}

可能最好的选择是让进程将自己置于 Windows job and apply the ProcessMemoryLimit 选项中。 (一个问题:如果进程已经在工作中,这将不起作用,例如,因为它正在 运行 作为启动脚本或计划任务。)您还可以使用相同的技术来限制内存使用您启动的另一个进程(或已经 运行ning)。

或者,您可以尝试启动一个使用 CreateResourceMemoryNotification 的线程来检测低物理内存情况并终止进程。但您可能会发现这会受到误报的影响。 (这当然不应该留在生产代码中。)

根据 Harry Johnston 的有用回答,我整理了一些代码,可以在程序的开头添加这些代码,以作为物理内存大小的一个因素对该程序的内存分配施加限制。

ULONGLONG aMemSize;
HANDLE aJob=::CreateJobObject(NULL, NULL);
JOBOBJECT_EXTENDED_LIMIT_INFORMATION aLimit;

    // Get physical memory and set process memory limit to 75% of physical memory
GetPhysicallyInstalledSystemMemory(&aMemSize);
aMemSize*=size_t(768);                      // convert kb to bytes and apply 75% factor
memset(&aLimit, 0, sizeof(aLimit));
aLimit.BasicLimitInformation.LimitFlags=JOB_OBJECT_LIMIT_PROCESS_MEMORY;
aLimit.ProcessMemoryLimit=aLimit.PeakProcessMemoryUsed=aLimit.JobMemoryLimit=
                                                aLimit.PeakJobMemoryUsed=aMemSize;
::SetInformationJobObject(aJob, JobObjectExtendedLimitInformation, &aLimit, sizeof(aLimit));
::AssignProcessToJobObject(aJob, ::GetCurrentProcess());