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

用calloc检测可分配内存,64位环境结果异常,求代码排查

问题:calloc检测可分配内存大小在64位环境下结果异常

我编写了一个通过calloc检测可分配内存大小的函数,使用mingw32(32位)编译后,程序输出1645943600字节(1569Mb),结果看似正常。但使用mingw64(64位)编译后,在配备8GB内存的Win10 64位虚拟机上输出21408144400字节(19Gb);在配备64GB内存的Win10 64位宿主机上输出101040000400字节(94Gb),这两个64位环境下的结果明显不符合实际物理内存情况。调用该函数时传入的参数为sizeof(char),请问我的代码是否存在问题?

我的代码

uint64_t erz_get_max_memory(const uint64_t size, const uint8_t enable_output)
{
    const char LOCAL_FUNCTION_NAME[] = "LOC:GMM";
    char *aramam = { 0 };
    uint64_t realloc_cnt = 0;
    uint64_t realloc_cnt_backup = 0;
    uint16_t filler = 10000;
    
    while(1)
    {
        aramam = (char *)calloc((realloc_cnt), (size));
        if(aramam == NULL)
        {
            if(filler == 1)
            {
                realloc_cnt -= 1;
                if(enable_output) erz_output(green, LOCAL_FUNCTION_NAME, "Possible Storage on this instance: [%llu] bytes -> [%llu] Elements\r\n", realloc_cnt * size, realloc_cnt);
                break;
            }
            realloc_cnt = realloc_cnt_backup;
            filler = 1;
        }
        else
        {
            free(aramam);
            realloc_cnt_backup = realloc_cnt;
            realloc_cnt += filler;
        }
    }
    if(aramam == NULL) free(aramam);
    return realloc_cnt;
}

问题分析与修复方案

核心问题:虚拟内存过度承诺

Windows的虚拟内存机制支持内存过度承诺:只要进程的虚拟地址空间还有剩余,calloc就会返回非NULL指针,哪怕物理内存+交换文件的总容量不足以支撑实际写入数据。你的代码只执行了内存分配,没有向分配的内存写入任何数据,因此检测到的是进程可用的虚拟地址空间大小,而非实际可使用的物理/可用内存。

代码细节问题

  • 初始realloc_cnt = 0,第一次调用calloc(0, size)的行为是C标准未定义的(允许返回NULL或可free的指针),不同编译器处理逻辑可能不一致。
  • 末尾if(aramam == NULL) free(aramam);是多余的,free(NULL)是合法操作,无需额外判断。
  • 当filler降到1后,每次仅递减1来试探,在大内存场景下效率极低,且依然无法规避虚拟内存过度承诺的问题。

修复建议

  1. 写入数据触发实际内存分配:分配内存后,向每个内存页写入数据(如0),强制系统分配物理内存,这样才能检测到实际可使用的内存容量。示例修改:
    else
    {
        // 获取系统页大小(Windows下可通过GetSystemInfo获取)
        SYSTEM_INFO sys_info;
        GetSystemInfo(&sys_info);
        size_t page_size = sys_info.dwPageSize;
        
        // 写入每个页,触发物理内存分配
        for (uint64_t i = 0; i < realloc_cnt * size; i += page_size)
        {
            // 捕获Windows内存不足异常
            __try {
                aramam[i] = 0;
            }
            __except(EXCEPTION_EXECUTE_HANDLER) {
                free(aramam);
                realloc_cnt = realloc_cnt_backup;
                filler = 1;
                goto retry_alloc;
            }
        }
        
        free(aramam);
        realloc_cnt_backup = realloc_cnt;
        realloc_cnt += filler;
    }
    retry_alloc:;
    
  2. 修正初始值:将realloc_cnt初始化为1,避免calloc(0, ...)的未定义行为。
  3. 改用二分法提升效率:当分配失败时,用二分法快速缩小试探范围,替代逐次减1的低效逻辑。
  4. 使用Windows原生API更可靠:直接调用GlobalMemoryStatusEx获取系统可用内存,或GetPhysicallyInstalledSystemMemory获取物理内存总大小,比内存试探法更高效准确。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 14:02:37