基准测试场景下g++编译内存统计结果与MSVC不一致问题
故障根因
- 你仅重载了C++14标准才新增的带size_t参数的sized operator delete,没有重载C++标准中最基础的无size参数的operator delete
- MSVC默认启用了高版本C++标准支持,调用delete时会优先匹配你写的带size参数的重载,所以统计逻辑正常运行
- GCC/Clang默认没有开启sized deallocation特性(或默认使用旧版C++标准),调用delete时会走系统默认的无size参数operator delete,你没有重载该版本,导致内存释放的统计完全失效,
totalFree数值不会累加,才会出现内存占用逐轮测试持续上涨的异常现象
修复步骤
1. 补充指针分配大小记录逻辑
修改AllocationMetrics结构体,增加映射表存储每个分配指针对应的内存大小,同时加锁保证多线程安全:
#include <unordered_map> #include <mutex> struct AllocationMetrics { uint64_t totalMemory = 0; uint64_t totalFree = 0; uint64_t maxMem = 0; std::unordered_map<void*, size_t> allocMap; std::mutex mtx; uint64_t getCurrentUsage() { std::lock_guard<std::mutex> lock(mtx); return totalMemory - totalFree; } void setMaxMem() { std::lock_guard<std::mutex> lock(mtx); uint64_t temp = getCurrentUsage(); if (temp > maxMem) maxMem = temp; } void resetMaxMem() { std::lock_guard<std::mutex> lock(mtx); maxMem = 0; } };
2. 重载所有版本的new/delete运算符
覆盖所有可能的内存分配释放入口,包括数组版本:
AllocationMetrics s_allocationMetrics; void* operator new(size_t size) { void* ptr = malloc(size); std::lock_guard<std::mutex> lock(s_allocationMetrics.mtx); s_allocationMetrics.totalMemory += size; s_allocationMetrics.allocMap[ptr] = size; return ptr; } void* operator new[](size_t size) { return operator new(size); } void operator delete(void* ptr) noexcept { std::lock_guard<std::mutex> lock(s_allocationMetrics.mtx); auto it = s_allocationMetrics.allocMap.find(ptr); if (it != s_allocationMetrics.allocMap.end()) { s_allocationMetrics.totalFree += it->second; s_allocationMetrics.allocMap.erase(it); } free(ptr); } void operator delete(void* ptr, size_t size) noexcept { std::lock_guard<std::mutex> lock(s_allocationMetrics.mtx); s_allocationMetrics.totalFree += size; s_allocationMetrics.allocMap.erase(ptr); free(ptr); } void operator delete[](void* ptr) noexcept { operator delete(ptr); } void operator delete[](void* ptr, size_t size) noexcept { operator delete(ptr, size); }
3. 编译时指定C++标准
编译命令增加-std=c++17参数,避免不同编译器默认标准差异导致的兼容问题:
g++ Source.cpp Functions.cpp benchmarking.cpp -std=c++17 -O2
额外注意事项
- 如果程序使用了自定义分配器、或者直接调用
malloc/free分配释放内存,这部分内存不会被new/delete的重载统计到,需要单独处理 - 单线程场景下可以去掉锁逻辑提升性能,多线程环境必须加锁避免统计错误和容器崩溃
内容的提问来源于stack exchange,提问作者Aleksander Markovskyy
相关产品推荐
相关产品推荐

