You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++堆内存过度分配:如何禁用交换内存触发std::bad_alloc?

在Windows 10中让C++内存分配失败时触发std::bad_alloc异常

问题原因

Windows 10默认采用虚拟内存过度承诺和懒加载分配机制:

  • new操作仅预留虚拟地址空间,不会立刻分配物理内存,直到首次访问内存页时才提交。
  • 物理内存耗尽后,系统会自动使用交换文件扩展可用内存,因此常规的new很难触发std::bad_alloc。

解决方案

通过以下修改,强制程序仅使用物理内存,并让内存分配失败时立刻抛出异常:

方法1:限制进程工作集+启用new异常模式

修改代码,结合Windows API限制进程不能使用交换文件,并配置new的异常行为:

#include <iostream>
#include <Windows.h>
#include <cstdlib>
#include <cstring>

int main()
{
    // 获取物理内存大小(单位:KB),限制进程工作集不超过物理内存
    SIZE_T physicalMemKB = GetPhysicallyInstalledSystemMemory() / 1024;
    if (!SetProcessWorkingSetSizeEx(
        GetCurrentProcess(),
        0,
        physicalMemKB,
        QUOTA_LIMITS_HARDWS_MIN_ENABLE
    )) {
        std::cerr << "Failed to configure working set: " << GetLastError() << "\n";
        return EXIT_FAILURE;
    }

    // 启用new操作符的异常模式,分配失败时抛出std::bad_alloc
    _set_new_mode(1);

    try {
        while (true) {
            int* ptr = new int[10000000L];
            // 写入数据触发内存提交,避免懒加载导致的虚假分配
            memset(ptr, 0, sizeof(int) * 10000000L);
        }
    } catch (const std::bad_alloc& e) {
        std::cout << "Allocation failed: " << e.what() << "\n";
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

方法2:自定义new操作符

直接替换默认的new实现,使用VirtualAlloc立刻提交物理内存,分配失败时主动抛出异常:

#include <iostream>
#include <Windows.h>
#include <cstdlib>
#include <new>

// 自定义new操作符
void* operator new(size_t size) {
    void* ptr = VirtualAlloc(
        NULL,
        size,
        MEM_COMMIT | MEM_RESERVE,
        PAGE_READWRITE
    );
    if (!ptr) {
        throw std::bad_alloc();
    }
    return ptr;
}

// 匹配的delete操作符
void operator delete(void* ptr) noexcept {
    VirtualFree(ptr, 0, MEM_RELEASE);
}

int main()
{
    // 可选:限制进程工作集,进一步确保不使用交换
    SIZE_T physicalMemKB = GetPhysicallyInstalledSystemMemory() / 1024;
    SetProcessWorkingSetSizeEx(
        GetCurrentProcess(),
        0,
        physicalMemKB,
        QUOTA_LIMITS_HARDWS_MIN_ENABLE
    );

    try {
        while (true) {
            int* ptr = new int[10000000L];
        }
    } catch (const std::bad_alloc& e) {
        std::cout << "Allocation failed: " << e.what() << "\n";
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

关键说明

  • SetProcessWorkingSetSizeEx的QUOTA_LIMITS_HARDWS_MIN_ENABLE参数强制进程的内存不能被分页到交换文件,物理内存耗尽时分配直接失败。
  • _set_new_mode(1)让标准库的new在底层调用HeapAlloc时启用异常模式,替代默认的返回NULL行为。
  • memset(或任何内存写入操作)是为了触发Windows的内存提交机制,否则仅预留地址空间不会消耗实际物理内存。

内容的提问来源于stack exchange,提问作者Ketrix

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 19:25:14