【Operating system experiment】Memory monitor experiment

1. Purpose of the experiment

Independently design and implement a memory monitor to gain a better understanding of memory management.

2. Experimental content

Design and implement a memory monitor under Windows system, use this memory monitor:

  1. It can display the memory usage in the current system in real time, including the layout of the system address space and the usage of physical memory;

  1. It can display the virtual address space layout and working set information of a process in real time.

3. Program design and implementation

1. Experimental environment

Operating system: Windows10

Development environment: Visual Studio 2022

2. Design ideas

① Get system information

  • 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

void GetNativeSystemInfo(

LPSYSTEM_INFO lpSystemInfo

);

Among them, LPSYSTEM_INFO is a pointer to SYSTEM_INFO.

  • information output

DWORD mem_size = (DWORD*)si.lpMaximumApplicationAddress - (DWORD*)si.lpMinimumApplicationAddress;

printDword(L"number of processors", si.dwNumberOfProcessors);

printStrFormatByte(L"Physical page size", si.dwPageSize);

printAddress(L"The minimum addressing space of the process: 0x", si.lpMinimumApplicationAddress);

printAddress(L"The maximum addressing address of the process: 0x", si.lpMaximumApplicationAddress);

printStrFormatByte(L"The size of the available space of the process: ", mem_size);

② Obtain physical memory information

The main data structures and functions used are MEMORYSTATUSEX and 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;

Before using this data structure, dwLength must be specified as sizeof(MEMORYSTATUSEX).

  • GlobalMemoryStatusEx

BOOL GlobalMemoryStatusEx(

LPMEMORYSTATUSEX lpBuffer

);

Among them, lpBuffer is a pointer to MEMORYSTAUSEX for saving information.

  • 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

);

Among them, pPerformanceInformation is a pointer to save the returned information, and cb needs to indicate the size of the PERFORMANCE_INFORMATION structure.

The main process of obtaining all processes is to obtain a snapshot of all processes first. Since the process information and number are dynamically changing, it is necessary to obtain a static information set first; secondly, similar to directory retrieval, sequential retrieval of snapshots is performed to obtain process information .

③ Create a process snapshot

  • CreateToolhelp32Snapshot

HANDLE CreateToolhelp32Snapshot(

DWORD dwFlags,

DWORD th32ProcessID

);

Among them, DWORD dwFlags indicates how many related attributes the function obtains into the snapshot, and DWORD th32ProcessID refers to the pid of the process to be obtained. 0 means the most recent process.

④ Traverse process

The data structure we use is PROCESSENTRY32, and the APIs we use are Process32First and 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) must be specified before use.

  • Process32First

BOOL Process32First(

HANDLE hSnapshot,

LPPROCESSENTRY32 lppe

);

HANDEL hSnapshot is obtained from the above CreateToolhelp32Snapshot, and LPPROCESSENTRY32 lppe is a pointer to PROCESSENTRY32.

  • Process32Next

BOOL Process32Next(

HANDLE hSnapshot,

LPPROCESSENTRY32 lppe

);

Among them, hSnapshot is the same, the difference is that lppe has a value at this time, which is used to save the status information of the process of the next item of the current item.

⑤ Get detailed information of a single process #

The main data structures used are: SYSTEM_INFO, MEMORY_BASIC_INFORMATION, and the main APIs used are: GetNativeSystemInfo, VirtualQueryEx and 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;

Among them, PVOID BaseAddress is the base address of the page area, DWORD AllocationProtect is to determine if the page area is initially acquired, then it is the protection method of the page area, SIZE_T RegionSize is the size of the current block, DWORD State is the state of the current page block, MEM_COMMIT, MEME_FREE, and MEM_RESERVE are the three states, DWORD Protect is the page access method in the current block, DWORD Type is the block type, and MEM_IMAGE, MEM_MAPPED, MEM_PRIVATE are the three types.

  • OpenProcess

HANDLE OpenProcess(

DWORD dwDesiredAccess,

BOOL bInheritHandle,

DWORD dwProcessId

);

其中,DWORD dwDesiredAccess是访问该进程的方式,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)。

  1. 编写、编译代码

在Visual Studio中编写C++代码,使用动态链接库,实现相应功能。

  1. 运行得到结果

  1. 编写、编译代码

在Visual Studio中编写C++代码,使用动态链接库,实现相应功能。

  1. 运行得到结果

四、实验结果及分析

操作过程中,我们通过对问题描述的分析,完成获取系统信息、获取物理内存信息、获取所有进程的基本信息、获取单个进程的详细信息,完成了内存监视器的设计,能实时地显示当前系统中内存的使用情况,包括系统地址空间的布局,物理内存的使用情况,也能实时显示某个进程的虚拟地址空间布局和工作集信息等,实验结果见附录。

五、实验收获与体会

“内存监视”是操作系统知识里非常重要的部分,通过本次实验,我进一步加深了对内存和进程概念的理解,深刻了解到内存监视的过程。

通过本实验,我掌握了许多在Windows下关于内存信息的系统调用函数,了解系统内部内存的工作方式和工作情况,对获取系统信息的API有了更加深入的了解,同时对操作系统内存分配方式有了进一步的印象。

Windows把每个进程的虚拟内存地址映射到物理内存地址,操作系统通过页式管理的方式对内存进行管理。

在亲自动手实验的过程中,我对本章知识点有了更深刻的理解,同时也复习了程序设计方面的知识,这次实验让我收获颇多!

项目源码及实验报告:https://github.com/YourHealer/OS-Memory-Monitor.git

Guess you like

Origin blog.csdn.net/ayaishere_/article/details/128709498