c ++ realize Windows memory monitoring

Problem Description

Design a memory monitor, real-time display the current system memory usage, including layout, physical memory usage of the system address space; able to display virtual address space layout and the working set of a process of real-time information.

Thinking

Get System Information

  1. 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;
  2. GetNativeSystemInfo

    Note INTELx86_64 system is best to use this function. Other equivalent toGetSystemInfo

    void GetNativeSystemInfo(
      LPSYSTEM_INFO lpSystemInfo
    );
    • LPSYSTEM_INFOPointing SYSTEM_INFOpointer
  3. Information output

    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);

    Note here print***that custom function.

  4. Show

    image_32

Get physical memory information

The main use of the data structures and functions have MEMORYSTATUSEXand GlobalMemoryStatusEx, PERFORMANCE_INFORMATIONandGetPerformanceInfo

  1. MEMORYSTATUSEX

    typedef struct _MEMORYSTATUSEX {
      DWORD     dwLength;
      DWORD     dwMemoryLoad;
      DWORDLONG ullTotalPhys;
      DWORDLONG ullAvailPhys;
      DWORDLONG ullTotalPageFile;
      DWORDLONG ullAvailPageFile;
      DWORDLONG ullTotalVirtual;
      DWORDLONG ullAvailVirtual;
      DWORDLONG ullAvailExtendedVirtual;
    } MEMORYSTATUSEX, *LPMEMORYSTATUSEX;

    Note that before using the data structure dwLengthmust be specified,dwLength = sizeof(MEMORYSTATUSEX)

  2. GlobalMemoryStatusEx

    BOOL GlobalMemoryStatusEx(
      LPMEMORYSTATUSEX lpBuffer
    );
    • lpBufferPointing MEMORYSTAUSEXa pointer, for storing information.
  3. 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;
  4. GetPerformanceInfo

    BOOL GetPerformanceInfo(
      PPERFORMANCE_INFORMATION pPerformanceInformation,
      DWORD                    cb
    );
    • pPerformanceInformation For storing pointer information pointing to the return
    • cbYou need to specify PERFORMANCE_INFORMATIONthe size of the structure
  5. Show results

    1577537259368

Obtain basic information about all processes

The main process is to get a snapshot of all processes, due process information and the number is dynamic, so you need to get a static collection of information; secondly, similar to the directory retrieval of snapshot sequential search process of obtaining information.

The process of creating snapshot

  1. CreateToolhelp32Snapshot

    HANDLE CreateToolhelp32Snapshot(
      DWORD dwFlags,
      DWORD th32ProcessID
    );
    • DWORD dwFlagsThis function is used to indicate how many of the properties acquired in the snapshot. Be specifically described with reference to the MSDN , this optional parameter isTH32CS_SNAPALL
    • DWORD th32ProcessIDpid process needs to be acquired. 0 indicates that the recent process.

Traversal process

data structure:PROCESSENTRY32

API: Process32First Process32Next

  1. 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;
    

    Note that you must specify before usedwSize = sizeof(PROCESSENTRY32)

  2. Process32First

    BOOL Process32First(
      HANDLE           hSnapshot,
      LPPROCESSENTRY32 lppe
    );
    • HANDEL hSnapshotFrom the above is CreateToolhelp32Snapshotobtained.
    • LPPROCESSENTRY32 lppeIt is PROCESSENTRY32a pointer
  3. Process32Next

    BOOL Process32Next(
      HANDLE           hSnapshot,
      LPPROCESSENTRY32 lppe
    );

    Meaning as above. Which hSnapshotis the same, except that lppethis time has value, for saving processes under one of the current item of status information.

Show results

1577539899792

For more information about a single process

The main use of the data structure are: SYSTEM_INFO(already described), MEMORY_BASIC_INFORMATION,

The main use of the API are: GetNativeSystemInfo(already described), VirtualQueryEx,OpenProcess

  1. 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 The base address of the page area
    • DWORD AllocationProtect; If this area of ​​the page is the initial acquisition, this is the way to protect their area of ​​the page
    • SIZE_T RegionSize Size of the current block
    • DWORD StateThe current state of the page block, MEM_COMMIT MEME_FREE MEM_RESERVEthree states
    • DWORD Protect Current page access method block
    • DWORD Type Block type threeMEM_IMAGE MEM_MAPPED MEM_PRIVATE
  2. OpenProcess

    HANDLE OpenProcess(
      DWORD dwDesiredAccess,
      BOOL  bInheritHandle,
      DWORD dwProcessId
    );
    • DWORD dwDesiredAccess Access to the process of the way, I have here the choices arePROCESS_ALL_ACCESS
    • BOOL bInheritHandle If true, the child process will inherit the process of the function returns a handle
    • DWORD dwProcessId To open the PID of the process
  3. VirtualQueryEx

    SIZE_T VirtualQueryEx(
      HANDLE                    hProcess,
      LPCVOID                   lpAddress,
      PMEMORY_BASIC_INFORMATION lpBuffer,
      SIZE_T                    dwLength
    );
    • hProcess To handle the query process
    • lpAddress The base address of the virtual memory block to query process
    • lpBuffer To save the pointer to the data point information is referred to aboveMEMORY_BASIC_INFORMATION
    • dwLength = sizeof(MEMORY_BASIC_INFORMATION)

1577541562291

Show results

Implement the following functions, it has been particularly shown described above.

1577544315864

Source

#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";
}

Guess you like

Origin www.cnblogs.com/harrypotterjackson/p/12113387.html