在C++开发中,获取系统物理内存占用峰值并实现进程监控接口是性能分析、资源管控场景的常见需求,不同操作系统提供了对应的原生接口支持,开发者可以根据运行环境选择适配的实现方案。

Windows系统下的实现方案
Windows系统提供了MEMORYSTATUSEX结构体和相关系统调用,可以获取系统全局的物理内存信息,同时结合进程相关的内存查询接口,就能实现内存峰值统计和进程监控功能。
获取系统物理内存信息
首先需要使用GlobalMemoryStatusEx函数获取系统的内存状态,该函数的参数需要传入MEMORYSTATUSEX结构体的实例,结构体中包含了物理内存的总量、可用量、已用量等核心数据。
#include <windows.h>
#include <iostream>
// 定义内存信息结构体,存储物理内存相关数据
typedef struct {
ULONGLONG total_phys; // 总物理内存,单位字节
ULONGLONG avail_phys; // 可用物理内存,单位字节
ULONGLONG used_phys; // 已用物理内存,单位字节
ULONGLONG peak_used; // 内存占用峰值,单位字节
} SysMemInfo;
// 获取Windows系统物理内存信息
bool get_win_sys_mem_info(SysMemInfo* mem_info) {
if (mem_info == nullptr) {
return false;
}
MEMORYSTATUSEX mem_status;
mem_status.dwLength = sizeof(mem_status);
if (!GlobalMemoryStatusEx(&mem_status)) {
return false;
}
mem_info->total_phys = mem_status.ullTotalPhys;
mem_info->avail_phys = mem_status.ullAvailPhys;
mem_info->used_phys = mem_status.ullTotalPhys - mem_status.ullAvailPhys;
// 初始化峰值为当前已用量,后续可动态更新
mem_info->peak_used = mem_info->used_phys;
return true;
}
实现内存峰值统计逻辑
内存峰值统计需要持续记录内存占用的历史最大值,每次获取新的内存占用数据后,和当前存储的峰值比较,如果新值更大就更新峰值。
#include <windows.h>
#include <iostream>
// 全局变量存储内存峰值,实际开发中可根据需求调整为类成员变量
static ULONGLONG g_mem_peak = 0;
// 更新内存占用峰值,返回最新的峰值
ULONGLONG update_mem_peak(ULONGLONG current_used) {
if (current_used > g_mem_peak) {
g_mem_peak = current_used;
}
return g_mem_peak;
}
// 获取当前内存峰值
ULONGLONG get_mem_peak() {
return g_mem_peak;
}
进程监控接口实现
进程监控需要获取指定进程的内存占用情况,Windows下可以通过OpenProcess打开进程句柄,再使用GetProcessMemoryInfo获取进程的内存信息。
#include <windows.h>
#include <psapi.h>
#include <iostream>
#pragma comment(lib, "psapi.lib")
// 进程内存信息结构体
typedef struct {
DWORD pid; // 进程ID
ULONGLONG working_set; // 进程工作集大小,即物理内存占用量,单位字节
ULONGLONG peak_ws; // 进程工作集峰值,单位字节
} ProcMemInfo;
// 获取指定进程的内存信息
bool get_proc_mem_info(DWORD pid, ProcMemInfo* proc_info) {
if (proc_info == nullptr) {
return false;
}
HANDLE h_proc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (h_proc == nullptr) {
return false;
}
PROCESS_MEMORY_COUNTERS pmc;
pmc.cb = sizeof(pmc);
bool ret = false;
if (GetProcessMemoryInfo(h_proc, &pmc, sizeof(pmc))) {
proc_info->pid = pid;
proc_info->working_set = pmc.WorkingSetSize;
proc_info->peak_ws = pmc.PeakWorkingSetSize;
ret = true;
}
CloseHandle(h_proc);
return ret;
}
Linux系统下的实现方案
Linux系统下可以通过读取/proc/meminfo文件获取系统物理内存信息,进程内存信息则可以从/proc/[pid]/status文件中读取,不需要依赖额外的系统库。
获取系统物理内存信息
/proc/meminfo文件中包含了系统内存的详细统计信息,其中MemTotal表示总物理内存,MemAvailable表示可用物理内存,两者差值就是已用物理内存。
#include <fstream>
#include <string>
#include <iostream>
// 获取Linux系统物理内存信息
bool get_linux_sys_mem_info(SysMemInfo* mem_info) {
if (mem_info == nullptr) {
return false;
}
std::ifstream mem_file("/proc/meminfo");
if (!mem_file.is_open()) {
return false;
}
std::string line;
ULONGLONG total_kb = 0;
ULONGLONG avail_kb = 0;
while (std::getline(mem_file, line)) {
if (line.find("MemTotal:") != std::string::npos) {
// 提取MemTotal后的数值,单位是KB
sscanf(line.c_str(), "MemTotal: %llu kB", &total_kb);
} else if (line.find("MemAvailable:") != std::string::npos) {
sscanf(line.c_str(), "MemAvailable: %llu kB", &avail_kb);
}
if (total_kb != 0 && avail_kb != 0) {
break;
}
}
mem_info->total_phys = total_kb * 1024; // 转换为字节
mem_info->avail_phys = avail_kb * 1024;
mem_info->used_phys = mem_info->total_phys - mem_info->avail_phys;
mem_info->peak_used = mem_info->used_phys;
return true;
}
进程监控接口实现
Linux下进程的内存信息存储在/proc/[pid]/status文件中,其中VmRSS字段表示进程占用的物理内存大小,VmHWM表示进程物理内存占用的峰值。
#include <fstream>
#include <string>
#include <sstream>
#include <iostream>
// 获取Linux下指定进程的内存信息
bool get_linux_proc_mem_info(DWORD pid, ProcMemInfo* proc_info) {
if (proc_info == nullptr) {
return false;
}
std::stringstream proc_path;
proc_path << "/proc/" << pid << "/status";
std::ifstream proc_file(proc_path.str());
if (!proc_file.is_open()) {
return false;
}
std::string line;
ULONGLONG rss_kb = 0;
ULONGLONG hwm_kb = 0;
while (std::getline(proc_file, line)) {
if (line.find("VmRSS:") != std::string::npos) {
sscanf(line.c_str(), "VmRSS: %llu kB", &rss_kb);
} else if (line.find("VmHWM:") != std::string::npos) {
sscanf(line.c_str(), "VmHWM: %llu kB", &hwm_kb);
}
if (rss_kb != 0 && hwm_kb != 0) {
break;
}
}
proc_info->pid = pid;
proc_info->working_set = rss_kb * 1024; // 转换为字节
proc_info->peak_ws = hwm_kb * 1024;
return true;
}
跨平台封装建议
实际开发中如果需要同时支持Windows和Linux系统,可以通过条件编译的方式封装统一的接口,上层调用不需要关心底层系统差异。
#ifdef _WIN32
#include <windows.h>
#include <psapi.h>
#pragma comment(lib, "psapi.lib")
#else
#include <fstream>
#include <string>
#include <sstream>
#endif
// 统一的内存信息获取接口
bool get_sys_mem_info(SysMemInfo* mem_info) {
#ifdef _WIN32
return get_win_sys_mem_info(mem_info);
#else
return get_linux_sys_mem_info(mem_info);
#endif
}
// 统一的进程内存信息获取接口
bool get_proc_mem_info(DWORD pid, ProcMemInfo* proc_info) {
#ifdef _WIN32
return get_win_proc_mem_info(pid, proc_info);
#else
return get_linux_proc_mem_info(pid, proc_info);
#endif
}
注意事项
- 内存峰值的统计需要持续运行监控逻辑,不能只获取一次数据,否则得到的只是当前时刻的占用值,不是峰值。
- Windows下打开进程句柄需要对应的权限,如果获取进程信息失败,需要检查当前程序是否有足够的权限访问目标进程。
- Linux下读取
/proc目录下的文件不需要特殊权限,但如果进程已经退出,对应的/proc/[pid]目录会消失,获取信息前需要先判断进程是否存在。 - 获取到的内存数值单位通常是字节,展示时可以根据需求转换为KB、MB、GB等单位,方便阅读。