Windows平台下C程序进程内存使用相关技术问题咨询
C程序内存监控问题解答
示例代码
#include <stdio.h> #include <windows.h> #include <psapi.h> void getMemInfo(){ PROCESS_MEMORY_COUNTERS_EX pmc; GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS *)&pmc, sizeof(pmc)); SIZE_T virtualMemUsedByMe = pmc.PrivateUsage; SIZE_T physMemUsedByMe = pmc.WorkingSetSize; printf("%ld, %ld\n", virtualMemUsedByMe, physMemUsedByMe); } int main() { double a[1000]; getMemInfo(); double *b = malloc(sizeof(double)*1000); getMemInfo(); free(b); getMemInfo(); return 0; }
问题解答
1. 为何每次运行内存输出有差异?是否误用pmc参数?
没有误用参数,PrivateUsage(私有虚拟内存)和WorkingSetSize(物理驻留内存)的用法是正确的。每次运行结果不同是因为Windows进程的内存环境本身就不是完全固定的:
- 进程启动时,系统加载依赖DLL的时机、内存碎片状态、CRT(C运行时库)初始化的额外开销都会有细微差异
- 系统的内存管理机制会动态调整进程的内存分配,比如物理内存不足时会把部分内存换出到分页文件,导致
WorkingSetSize波动 - 即使是相同的代码,不同运行实例的栈、堆初始化位置也可能不同,带来内存统计的细微差别
2. 如何及时记录内存分配前后的使用情况?
- 紧挨着调用监控函数:确保
getMemInfo()直接写在malloc/free的前后,中间不要插入其他可能触发内存分配的操作(比如额外的printf、系统调用等),避免干扰统计结果 - 封装宏或包装函数:可以把内存监控和分配操作绑定,减少手动调用的失误,比如:
#define MALLOC_AND_RECORD(size) ({ \ getMemInfo(); \ void* ptr = malloc(size); \ getMemInfo(); \ ptr; \ }) #define FREE_AND_RECORD(ptr) ({ \ getMemInfo(); \ free(ptr); \ getMemInfo(); \ })
或者封装自定义的malloc/free:
void* tracked_malloc(size_t size) { getMemInfo(); void* res = malloc(size); getMemInfo(); return res; } void tracked_free(void* ptr) { getMemInfo(); free(ptr); getMemInfo(); }
- 注意编译模式差异:调试版CRT会给
malloc分配的内存加上额外的调试信息(比如边界检查、内存块标记),导致内存统计数值比Release版大,测试时要保持编译模式一致
3. 优化C项目时,应选用哪个pmc参数作为性能基准?
要根据你的优化目标来选:
- 优化物理内存占用(比如低内存设备、服务器场景):选
WorkingSetSize,它代表当前进程实际占用的物理内存。但注意这个值会被系统的内存置换机制影响,建议多次采样取稳定后的平均值 - 优化虚拟内存占用(比如32位程序避免地址空间耗尽):选
PrivateUsage,它统计的是进程独占的虚拟内存,不包含共享的DLL、系统内存等,能准确反映进程自身的内存开销 - 排查内存泄漏:优先看
PrivateUsage,因为泄漏的内存会持续占用私有虚拟内存,而WorkingSetSize可能被系统换出,无法准确体现泄漏情况 - 补充:如果需要更精准的堆内存统计,建议用CRT自带的内存跟踪函数(比如
_CrtMemCheckpoint、_heapwalk),因为GetProcessMemoryInfo统计的是整个进程的内存,包括栈、DLL、内核对象等,无法区分堆内存的具体使用情况
内容的提问来源于stack exchange,提问作者Lex
相关产品推荐
相关产品推荐

