问题描述
设计一个内存监视器, 能实时地显示当前系统中内存的使用情况, 包括系统地址空间的布局, 物理内存的使用情况; 能实时显示某个进程的虚拟地址空间布局和工作集信息等.
思路
获取系统信息
- SYSTEM_INFO
- typedef struct _SYSTEM_INFO {
- union {
- DWORD dwOemId;
- struct {
- Word wProcessorArchitecture;
- Word wReserved;
- } DUMMYSTRUCTNAME;
- } DUMMYUNIONNAME;
- DWORD dwPageSize;
- LPVOID lpMinimumApplicationAddress;
- LPVOID lpMaximumApplicationAddress;
- DWORD_PTR dwActiveProcessorMask;
- DWORD dwNumberOfProcessors;
- DWORD dwProcessorType;
- DWORD dwAllocationGranularity;
- Word wProcessorLevel;
- Word wProcessorRevision;
- } SYSTEM_INFO, *LPSYSTEM_INFO;
- GetNativeSystemInfo
注意 INTELx86_64 体系最好用这个函数. 其他的等价于 GetSystemInfo
- void GetNativeSystemInfo(
- LPSYSTEM_INFO lpSystemInfo
- );
LPSYSTEM_INFO 指向 SYSTEM_INFO 的指针
信息输出
- DWORD mem_size = (DWORD*)si.lpMaximumApplicationAddress - (DWORD*)si.lpMinimumApplicationAddress;
- printDword(L"处理器个数", si.dwNumberOfProcessors);
- printStrFormatByte(L"物理页大小", si.dwPageSize);
- printAddress(L"进程最小寻址空间: 0x", si.lpMinimumApplicationAddress);
- printAddress(L"进程最大寻址地址: 0x", si.lpMaximumApplicationAddress);
- printStrFormatByte(L"进程可用空间大小:", mem_size);
注意这里的 print*** 是自定义函数.
展示
获取物理内存信息
主要使用到的数据结构和函数有 MEMORYSTATUSEX 与 GlobalMemoryStatusEx, PERFORMANCE_INFORMATION 与 GetPerformanceInfo
- MEMORYSTATUSEX
- typedef struct _MEMORYSTATUSEX {
- DWORD dwLength;
- DWORD dwMemoryLoad;
- DWORDLONG ullTotalPhys;
- DWORDLONG ullAvailPhys;
- DWORDLONG ullTotalPageFile;
- DWORDLONG ullAvailPageFile;
- DWORDLONG ullTotalVirtual;
- DWORDLONG ullAvailVirtual;
- DWORDLONG ullAvailExtendedVirtual;
- } MEMORYSTATUSEX, *LPMEMORYSTATUSEX;
注意在使用该数据结构之前, dwLength 必须进行指定, dwLength = sizeof(MEMORYSTATUSEX)
- GlobalMemoryStatusEx
- BOOL GlobalMemoryStatusEx(
- LPMEMORYSTATUSEX lpBuffer
- );
lpBuffer 是指向 MEMORYSTAUSEX 的指针, 用于保存信息.
- PERFORMANCE_INFORMATION
- typedef struct _PERFORMANCE_INFORMATION {
- DWORD cb;
- SIZE_T CommitTotal;
- SIZE_T CommitLimit;
- SIZE_T CommitPeak;
- SIZE_T PhysicalTotal;
- SIZE_T PhysicalAvailable;
- SIZE_T SystemCache;
- SIZE_T KernelTotal;
- SIZE_T KernelPaged;
- SIZE_T KernelNonpaged;
- SIZE_T PageSize;
- DWORD HandleCount;
- DWORD ProcessCount;
- DWORD ThreadCount;
- } PERFORMANCE_INFORMATION, *PPERFORMANCE_INFORMATION, PERFORMACE_INFORMATION, *PPERFORMACE_INFORMATION;
- GetPerformanceInfo
- BOOL GetPerformanceInfo(
- PPERFORMANCE_INFORMATION pPerformanceInformation,
- DWORD cb
- );
- pPerformanceInformation
指向用于保存返回信息的指针
cb 需要指明
PERFORMANCE_INFORMATION
结构体的大小
效果展示
获取所有进程的基本信息
主要过程是先获取所有进程的一个 snapshot, 由于进程信息和数量是动态变化的, 所以需要先获取一个静态的信息集; 其次, 类似于目录检索对 snapshot 进行顺序检索, 获取进程信息.
创建进程 snapshot
- CreateToolhelp32Snapshot
- HANDLE CreateToolhelp32Snapshot(
- DWORD dwFlags,
- DWORD th32ProcessID
- );
DWORD dwFlags 用于表明该函数获取多少有关属性到 snapshot 中. 具体说明可参考 MSDN, 这里选用的参数是 TH32CS_SNAPALL
DWORD th32ProcessID 需要获取的进程的 pid.0 表示是最近的进程.
遍历进程
数据结构: PROCESSENTRY32
- API: Process32First Process32Next
- PROCESSENTRY32
- typedef struct tagPROCESSENTRY32 {
- DWORD dwSize;
- DWORD cntUsage;
- DWORD th32ProcessID;
- ULONG_PTR th32DefaultHeapID;
- DWORD th32ModuleID;
- DWORD cntThreads;
- DWORD th32ParentProcessID;
- LONG pcPriClassBase;
- DWORD dwFlags;
- TCHAR szExeFile[MAX_PATH];
- } PROCESSENTRY32, *PPROCESSENTRY32;
注意在使用前必须指定 dwSize = sizeof(PROCESSENTRY32)
- Process32First
- BOOL Process32First(
- HANDLE hSnapshot,
- LPPROCESSENTRY32 lppe
- );
HANDEL hSnapshot 就是从上述
CreateToolhelp32Snapshot
获得的.
LPPROCESSENTRY32 lppe
就是 PROCESSENTRY32 的指针
- Process32Next
- BOOL Process32Next(
- HANDLE hSnapshot,
- LPPROCESSENTRY32 lppe
- );
含义同上. 其中 hSnapshot 是同一个, 不同的是 lppe 此时有了值, 用于保存当前项的下一项的进程的状态信息.
效果展示
获取单个进程的详细信息
使用到的主要数据结构有: SYSTEM_INFO (已介绍),MEMORY_BASIC_INFORMATION,
使用到的主要 API 有: GetNativeSystemInfo(已介绍),VirtualQueryEx, OpenProcess
- MEMORY_BASIC_INFORMATION
- typedef struct _MEMORY_BASIC_INFORMATION {
- PVOID BaseAddress;
- PVOID AllocationBase;
- DWORD AllocationProtect;
- SIZE_T RegionSize;
- DWORD State;
- DWORD Protect;
- DWORD Type;
- } MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;
PVOID BaseAddress 页面区域的基地址
DWORD AllocationProtect;
如果这个页面区域是初始获取的, 这里就是其页面区域的保护方式
SIZE_T RegionSize 当前块的大小
DWORD State 当前页面块的状态, MEM_COMMIT MEME_FREE MEM_RESERVE 三种状态
DWORD Protect 当前块中的页面访问方式
DWORD Type 块类型, 三种 MEM_IMAGE MEM_MAPPED MEM_PRIVATE
- OpenProcess
- HANDLE OpenProcess(
- DWORD dwDesiredAccess,
- BOOL bInheritHandle,
- DWORD dwProcessId
- );
- DWORD dwDesiredAccess
访问该进程的方式, 我这里选用的是 PROCESS_ALL_ACCESS
BOOL bInheritHandle 如果为真, 该进程的子进程也将继承该函数的返回句柄
DWORD dwProcessId 要打开的进程的 PID
- VirtualQueryEx
- SIZE_T VirtualQueryEx(
- HANDLE hProcess,
- LPCVOID lpAddress,
- PMEMORY_BASIC_INFORMATION lpBuffer,
- SIZE_T dwLength
- );
hProcess 要查询的进程的句柄
lpAddress 要查询的进程的虚存的块的基地址
lpBuffer 指向要保存相关信息的数据的指针就是上文提到的
- MEMORY_BASIC_INFORMATION
- dwLength = sizeof(MEMORY_BASIC_INFORMATION)
效果展示
实现的功能如下, 具体的展示已在上文说明.
源代码
- #include <iostream>
- #include <stdio.h>
- #include <string.h>
- #include <tchar.h>
- #include <iomanip>
- #include <Windows.h>
- #include <Tlhelp32.h>
- #include <shlwapi.h>
- #include <Psapi.h>
- #pragma comment(lib,"Shlwapi.lib")
- #pragma comment(lib, "Psapi.Lib")
- #pragma comment(lib,"Kernel32.lib")
- using namespace std;
- enum ProgramState { QUERY_SYS_INFO, QUERY_MEM_INFO, QUERY_PRE_INFO, EXIT };
- // 查询系统配置信息
- void getSystemInfo();
- // 物理内存使用情况
- void getMemoryInfo();
- // 打印所有进程的基本信息
- void getProcessInfo();
- // 获得单个内存的使用情况
- void showSingleProcessMemDetail(int PID);
- void help();
- int main()
- {
- setlocale(LC_ALL, "");
- int state = ProgramState::EXIT;// 默认为退出状态
- while (1)
- {
- help();
- std::cout.fill(' ');
- std::cout.setf(iOS::dec);// 确保 cout 输出为十进制
- cin>> state;
- std::cout <<"\n";
- if (state == ProgramState::QUERY_SYS_INFO)
- {
- getSystemInfo();
- }
- else if (state == ProgramState::QUERY_MEM_INFO)
- {
- getMemoryInfo();
- }
- else if (state == ProgramState::QUERY_PRE_INFO)
- {
- getProcessInfo(); // 当前所有运行进程基本信息
- std::cout << "输入进程 PID 以查看其虚拟内存信息" << endl;
- int PID;
- cin>> PID;
- showSingleProcessMemDetail(PID);
- }
- else if (state == ProgramState::EXIT)
- {
- return 0; // 结束程序的运行
- }
- }
- return 0;
- }
- // 将字节数转为字符串打印输出
- inline void printStrFormatByte(const WCHAR* info, DWORDLONG bytes)
- {
- TCHAR tmp[MAX_PATH];
- ZeroMemory(tmp, sizeof(tmp));
- StrFormatByteSize(bytes, tmp, MAX_PATH);
- wcout << info << tmp << endl;
- return;
- }
- // 打印地址
- inline void printAddress(const WCHAR* info, LPVOID addr)
- {
- wcout << info << hex << setw(8) << addr << endl;
- }
- inline void printDword(const WCHAR* info, DWORDLONG dw)// 将 DWORD 转为 DWORDLONG
- {
- wcout << info;
- std::cout << dw << endl;
- }
- // 查询系统配置信息
- void getSystemInfo()
- {
- SYSTEM_INFO si;
- ZeroMemory(&si, sizeof(si));
- GetNativeSystemInfo(&si);
- DWORD mem_size = (DWORD*)si.lpMaximumApplicationAddress - (DWORD*)si.lpMinimumApplicationAddress;
- printDword(L"处理器个数", si.dwNumberOfProcessors);
- printStrFormatByte(L"物理页大小", si.dwPageSize);
- printAddress(L"进程最小寻址空间: 0x", si.lpMinimumApplicationAddress);
- printAddress(L"进程最大寻址地址: 0x", si.lpMaximumApplicationAddress);
- printStrFormatByte(L"进程可用空间大小:", mem_size);
- return;
- }
- // 物理内存使用情况
- void getMemoryInfo()
- {
- MEMORYSTATUSEX mem_stat;
- ZeroMemory(&mem_stat, sizeof(mem_stat));
- mem_stat.dwLength = sizeof(mem_stat);// 必须执行这一步
- GlobalMemoryStatusEx(&mem_stat); // 取得内存状态
- std::cout << "内存利用率 \t" << mem_stat.dwMemoryLoad << endl;
- printStrFormatByte(L"物理内存: \t", mem_stat.ullTotalPhys);
- printStrFormatByte(L"可用物理内存: \t", mem_stat.ullAvailPhys);
- printStrFormatByte(L"总共页文件大小: \t", mem_stat.ullTotalPageFile);
- printStrFormatByte(L"空闲页文件大小: \t", mem_stat.ullAvailPageFile);
- printStrFormatByte(L"虚拟内存大小: \t", mem_stat.ullTotalVirtual);
- printStrFormatByte(L"空闲虚拟内存大小:\t", mem_stat.ullAvailVirtual);
- printStrFormatByte(L"空闲拓展内存大小:\t", mem_stat.ullAvailExtendedVirtual);
- cout << endl << endl;
- PERFORMANCE_INFORMATION pi;
- GetPerformanceInfo(&pi, sizeof(pi));
- DWORDLONG page_size = pi.PageSize;
- printStrFormatByte(L"Commit Total \t", pi.CommitTotal * page_size);
- printStrFormatByte(L"Commit Limit \t", pi.CommitLimit * page_size);
- printStrFormatByte(L"Commit Peak \t", pi.CommitPeak * page_size);
- printStrFormatByte(L"Physical Memory \t", pi.PhysicalTotal * page_size);
- printStrFormatByte(L"Physical Memory Avaliable", pi.PhysicalAvailable * page_size);
- printStrFormatByte(L"System Cache \t", page_size*pi.SystemCache);
- printStrFormatByte(L"Kerbel Total \t", page_size * pi.KernelTotal);
- printStrFormatByte(L"Kernel Paged \t", page_size * pi.KernelPaged);
- printStrFormatByte(L"Kernel Nonpaged \t", page_size * pi.KernelNonpaged);
- printStrFormatByte(L"Page Size \t", page_size * pi.PageSize);
- printDword(L"Handle Count \t", page_size * pi.HandleCount);
- printDword(L"Process Count \t", page_size * pi.ProcessCount);
- printDword(L"Thread Count \t", page_size * pi.ThreadCount);
- }
- // 打印所有进程的基本信息
- void getProcessInfo()
- {
- // 创建进程 snapshot
- HANDLE h_process_snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
- if (h_process_snapshot == INVALID_HANDLE_VALUE)
- {
- cout << "CreateToolhelp32Snapshot 调用失败!\n";
- exit(-1);
- }
- PROCESSENTRY32 process_entry;
- process_entry.dwSize = sizeof(process_entry);// 必须要指定大小
- // 循环遍历输出所有进程的信息
- if (Process32First(h_process_snapshot, &process_entry))
- {
- wcout << setiosflags(iOS::left) << setw(40) << L"Process Name";
- cout << setiosflags(iOS::right) << setw(15) << "PID";
- wcout << L"\t\t 线程数量" << endl << endl;
- do
- {
- wcout << setiosflags(iOS::left) << setw(40) << process_entry.szExeFile;// 进程名
- std::cout << "\t" << setw(7) << process_entry.th32ProcessID;//pid
- std::cout << "\t" << setw(3) << process_entry.cntThreads << endl;// 线程数目
- } while (Process32Next(h_process_snapshot, &process_entry));
- }
- CloseHandle(h_process_snapshot);
- }
- // 显示当前块页面访问方式
- void printPageProtection(DWORD dwTarget)
- {
- const int width = 20;
- switch (dwTarget)
- {
- case(PAGE_READONLY):
- {
- std::cout << setiosflags(iOS::left) << setw(width) << "READONLY";
- break;
- }
- case(PAGE_GUARD):
- {
- std::cout << setiosflags(iOS::left) << setw(width) << "GUARD";
- break;
- }
- case(PAGE_NOCACHE):
- {
- std::cout << setiosflags(iOS::left) << setw(width) << "NOCACHE";
- break;
- }
- case(PAGE_NOACCESS):
- {
- std::cout << setiosflags(iOS::left) << setw(width) << "NOACCESS";
- break;
- }
- case(PAGE_READWRITE):
- {
- std::cout << setiosflags(iOS::left) << setw(width) << "READWRITE";
- break;
- }
- case(PAGE_WRITECOPY):
- {
- std::cout << setiosflags(iOS::left) << setw(width) << "WRITECOPY";
- break;
- }
- case(PAGE_EXECUTE):
- {
- std::cout << setiosflags(iOS::left) << setw(width) << "EXECUTE";
- break;
- }
- case(PAGE_EXECUTE_READ):
- {
- std::cout << setiosflags(iOS::left) << setw(width) << "EXECUTE_READ";
- break;
- }
- case(PAGE_EXECUTE_READWRITE):
- {
- std::cout << setiosflags(iOS::left) << setw(width) << "EXECUTE_READWRITE";
- break;
- }
- case(PAGE_EXECUTE_WRITECOPY):
- {
- std::cout << setiosflags(iOS::left) << setw(width) << "EXECUTE_WRITECOPY";
- break;
- }
- default:
- break;
- }
- }
- // 输出单个进程的详细信息
- void showSingleProcessMemDetail(int PID)
- {
- SYSTEM_INFO si;
- ZeroMemory(&si, sizeof(si));
- GetNativeSystemInfo(&si); // 获得系统信息
- // 循环访问整个进程地址空间
- LPCVOID p_begin = (LPVOID)si.lpMinimumApplicationAddress; //p_begin 指向开始的地址
- std::cout.setf(iOS::left);
- // 输出表头
- wcout << setiosflags(iOS::left) << setw(21) << L"块地址"
- << setw(10) << L"块大小"
- << setw(10) << L"块内页状态"
- << setw(12) << L"块内页保护方式"
- << setw(10) << L"块类型" << endl;
- HANDLE h_process = OpenProcess(PROCESS_ALL_ACCESS, 0, PID); // 得到 PID 的值
- if (h_process == INVALID_HANDLE_VALUE)
- {
- std::cout << "Failed to OpenProcess" << endl;
- exit(-1);
- }
- MEMORY_BASIC_INFORMATION mem; // 虚拟内存空间的基本信息结构
- ZeroMemory(&mem, sizeof(mem));
- while (p_begin < (LPVOID)si.lpMaximumApplicationAddress)
- {
- // 查询进程在 p_begin 开始的块信息
- VirtualQueryEx(
- h_process, // 进程句柄
- p_begin, // 开始位置的地址
- &mem, // 缓冲区
- sizeof(mem));
- // 块结束地址
- LPCVOID p_end = (PBYTE)p_begin + mem.RegionSize;
- // 输出块起始, 结束地址
- std::cout << hex << setw(8) << setfill('0') << (DWORD*)p_begin
- << "-"
- << hex << setw(8) << setfill('0') << (DWORD*)p_end;
- // 输出块大小
- TCHAR tmp[MAX_PATH];
- ZeroMemory(tmp, sizeof(tmp));
- StrFormatByteSize(mem.RegionSize, tmp, MAX_PATH);
- std::wcout << "\t" << setw(8) << tmp;
- // 输出块的状态
- std::cout.fill(' ');
- if (mem.State == MEM_COMMIT)
- {
- std::cout << setw(10) << "已提交";
- }
- else if (mem.State == MEM_FREE)
- {
- std::cout << setw(10) << "空闲";
- }
- else if (mem.State == MEM_RESERVE)
- {
- std::cout << setw(10) << "保留";
- }
- // 显示块内页的保护方式
- if (mem.Protect == 0 && mem.State != MEM_FREE)
- {
- mem.Protect = PAGE_READONLY;
- }
- printPageProtection(mem.Protect);
- // 显示块的类型 邻近页面物理存储器类型指的是与给定地址所在页面相同的存储器类型
- std::cout.fill(' ');
- if (mem.Type == MEM_IMAGE)
- {
- std::cout << "\t\tImage";
- }
- else if (mem.Type == MEM_PRIVATE)
- {
- std::cout << "\t\tPrivate";
- }
- else if (mem.Type == MEM_MAPPED)
- {
- std::cout << "\t\tMapped";
- }
- cout << endl;
- // 移动块指针获得下一个块
- if (p_begin == p_end)// 部分进程如 0 号进程无法进行空间遍历
- break;
- p_begin = p_end;
- }
- }
- void help()
- {
- std::cout << "\n\nMenu:" << endl
- << ProgramState::QUERY_SYS_INFO << "- 查看系统信息" << endl
- << ProgramState::QUERY_MEM_INFO << "- 查看内存情况" << endl
- << ProgramState::QUERY_PRE_INFO << "- 查看当前运行进程信息及其虚拟地址空间布局和工作集信息" << endl
- << ProgramState::EXIT << "- 退出 \ n\n";
- }
来源: http://www.bubuko.com/infodetail-3355113.html