用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来试探,在大内存场景下效率极低,且依然无法规避虚拟内存过度承诺的问题。
修复建议
- 写入数据触发实际内存分配:分配内存后,向每个内存页写入数据(如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:; - 修正初始值:将
realloc_cnt初始化为1,避免calloc(0, ...)的未定义行为。 - 改用二分法提升效率:当分配失败时,用二分法快速缩小试探范围,替代逐次减1的低效逻辑。
- 使用Windows原生API更可靠:直接调用
GlobalMemoryStatusEx获取系统可用内存,或GetPhysicallyInstalledSystemMemory获取物理内存总大小,比内存试探法更高效准确。
内容的提问来源于stack exchange,提问作者Erz
相关产品推荐
相关产品推荐

