Linux下C++程序中获取abc.exe最大内存占用并存储至变量
我希望测量abc.exe在gen.exe生成的随机测试用例下的最大内存占用。当前已编写如下C++代码,用于循环调用gen.exe生成测试用例test.in,再调用abc.exe处理该测试用例:
#include <bits/stdc++.h> using namespace std; int main() { int i = 0; while (true) { string si = to_string(i); cout << i << "\n"; if (system(("echo " + si + "| ./gen.exe > test.in").c_str())) // gen.exe 是测试用例生成器 { cout << "gen error\n"; break; } if (system(("./abc.exe < test.in > a.out").c_str())) // abc.exe 是待测试程序 { cout << "abc error\n"; break; } i++; } }
我知道可以使用time -v ./abc.exe查看内存使用情况,但该结果仅输出到终端,无法保存到变量中,请问该如何实现?
方法1:重定向time输出到文件或变量
time -v的输出默认走标准错误(stderr),不是标准输出(stdout),直接用>重定向不会生效,得把stderr也重定向。
保存到文件
修改调用abc.exe的命令,把内存日志存到单独文件里:
if (system(("time -v ./abc.exe < test.in > a.out 2> mem_log_" + si + ".txt").c_str()))
每个测试用例的内存数据会存在mem_log_0.txt、mem_log_1.txt这类文件里,之后从中提取Maximum resident set size(最大驻留内存)的值就行。
捕获输出到C++变量
要是想直接把内存数据读到程序变量里,用popen代替system,读取time -v的输出:
// 替换原来调用abc.exe的system代码段 FILE* pipe = popen(("time -v ./abc.exe < test.in > a.out 2>&1").c_str(), "r"); if (!pipe) { cout << "abc error\n"; break; } char buffer[1024]; string mem_output; while (fgets(buffer, sizeof(buffer), pipe) != nullptr) { mem_output += buffer; } int status = pclose(pipe); if (status != 0) { cout << "abc error\n"; break; } // 解析最大内存值 size_t pos = mem_output.find("Maximum resident set size"); if (pos != string::npos) { pos = mem_output.find(":", pos); string mem_str = mem_output.substr(pos + 1); // 去掉空格和换行符 mem_str.erase(remove_if(mem_str.begin(), mem_str.end(), ::isspace), mem_str.end()); long long max_mem = stoll(mem_str); cout << "测试用例 " << i << " 最大内存占用: " << max_mem << " KB\n"; // 可以把max_mem存入数组或文件,方便后续统计最大值 }
这里2>&1是把stderr重定向到stdout,让popen能读到time -v的输出,再解析出需要的内存字段。
方法2:用getrusage系统调用直接获取
不想依赖time命令的话,用fork+exec启动abc.exe,再用getrusage获取子进程的资源使用情况,这种方法更直接:
#include <sys/wait.h> #include <sys/resource.h> // 替换原来调用abc.exe的system代码段 pid_t pid = fork(); if (pid == -1) { perror("fork失败"); break; } else if (pid == 0) { // 子进程执行abc.exe freopen("test.in", "r", stdin); freopen("a.out", "w", stdout); execl("./abc.exe", "./abc.exe", nullptr); perror("exec失败"); exit(1); } else { // 父进程等待子进程结束并读取资源数据 int status; waitpid(pid, &status, 0); if (WEXITSTATUS(status) != 0) { cout << "abc error\n"; break; } struct rusage usage; getrusage(RUSAGE_CHILDREN, &usage); long long max_mem = usage.ru_maxrss; // Linux下单位是KB,macOS下是字节 cout << "测试用例 " << i << " 最大内存占用: " << max_mem << " KB\n"; }
这种方式不用解析字符串,也不依赖外部命令,适合集成到C++程序里。注意ru_maxrss的单位在不同系统有差异,需要根据环境调整。
方法3:用ps实时监控(适合调试)
要是需要实时看abc.exe的内存变化,可以用ps命令循环读取,但精度不如前两种,适合临时调试:
// 后台启动abc.exe system("./abc.exe < test.in > a.out &"); // 需要获取abc.exe的PID,这里可以用pidof或者其他方式,示例中假设已经拿到pid pid_t pid = ...; long long max_mem = 0; string cmd = "ps -o rss= -p " + to_string(pid); FILE* pipe = popen(cmd.c_str(), "r"); char buffer[64]; while (fgets(buffer, sizeof(buffer), pipe) != nullptr) { long long current = stoll(buffer); if (current > max_mem) max_mem = current; usleep(10000); // 每10毫秒检查一次 } pclose(pipe); cout << "最大内存占用: " << max_mem << " KB\n";
这种方法需要处理进程后台运行和PID获取,复杂度较高,一般优先用前两种方法。
内容的提问来源于stack exchange,提问作者Darkolin

