【问题标题】:Windows freezes due to excessive memory allocation of 64-bit process由于 64 位进程的内存分配过多,Windows 冻结
【发布时间】:2016-08-10 09:15:10
【问题描述】:

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

所以我有两个问题:

  • 进程能否限制其内存消耗? Windows 中是否有可以设置内存限制的系统调用,以便超出限制的分配将失败而不是使整个系统崩溃?

  • 或者,有没有办法设置系统范围的每个进程的内存限制或为特定应用程序设置限制?

这是导致我的计算机死机的示例代码。它是使用 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;
}

【问题讨论】:

  • @HansPassant 谢谢,但这不是我需要的。只是为了澄清:我不是试图操纵进程的物理内存限制(又名“工作集”),我试图限制进程的虚拟内存的大小。当源代码可用时(例如,通过系统调用)或在源代码不可用时通过管理工具在外部进行,我尝试在程序内部进行。
  • @HarryJohnston 感谢您的回复。你说它不应该让整个系统崩溃,你自己试过吗?它在三个不同的场合一直发生在我身上,都在不同的机器上使用不同的 Windows 版本,在完全不同的情况下涉及不同的软件。它也发生在 Linux 上,但我知道如何在那里解决它。我几乎不相信这只是巧合。
  • @HarryJohnston 感谢哈利的帮助。也许 8 GB 机器上的 12 GB 并没有让它承受足够的压力。尝试将其增加一倍或三倍。无论如何,我添加了导致计算机死机的代码。现在刚试了一下,在计算机无响应 30 分钟后不得不硬重启。即使最终它会恢复,我认为应该清楚为什么我要采取某种安全措施来防止流氓程序长时间禁用计算机,特别是如果该流氓程序是我自己的(不完美) 程序。
  • 我的 Windows 7 测试机在运行您的程序时只是间歇性地无响应。但 Windows 8 可能会受到更严重的影响。

标签: c++ windows memory memory-management administrator


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

    根据 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());
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-08-16
      • 2010-09-07
      • 2021-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-24
      • 2011-07-11
      相关资源
      最近更新 更多