《windows系统编程》——内存基础与相关结构

《Windows系统编程》——内存基础与相关结构 笔记

课堂笔记

WINAPI学习

在这堂课也有点摸清楚一些规律了,WINAPI 中的一些结构体,除了定义结构体本身以外还会定义它的指针类型,一般在该变量类型名前加上前缀 lp(LP)。

GetSystemInfo

GetSystemInfo 函数用于获取系统信息,传入参数位 SYSTEM_INFO *,没有返回值,获取的系统信息通过 SYSTEM_INFO 结构体返回,结构体定义如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
typedef struct _SYSTEM_INFO {
union {
DWORD dwOemId; // Obsolete field...do not use
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;

其中

  • dwPageSize 为内存页大小
  • lpMinimumApplicationAddress 为进程可用的最小内存地址
  • lpMaximumApplicationAddress 为进程可用的最大内存地址

我们可以通过调试手段方便地查看结构体各个成员

MemoryStatusEx

MemoryStatusEx 函数用于获取当前电脑内存信息。传入参数类型为 LPMEMORYSTATUSEX,也就是 MEMORYSTATUSEX * 类型。这个类型的结构体定义如下:

1
2
3
4
5
6
7
8
9
10
11
typedef struct _MEMORYSTATUSEX {
DWORD dwLength;
DWORD dwMemoryLoad;
DWORDLONG ullTotalPhys;
DWORDLONG ullAvailPhys;
DWORDLONG ullTotalPageFile;
DWORDLONG ullAvailPageFile;
DWORDLONG ullTotalVirtual;
DWORDLONG ullAvailVirtual;
DWORDLONG ullAvailExtendedVirtual;
} MEMORYSTATUSEX, *LPMEMORYSTATUSEX;

除了 dwLength 外,第一个参数就是 dwMemoryLoad,它告诉了我们当前物理内存占用情况,也就是我们任务管理器看到的内存占用百分比,写一个程序输出就会发现它与任务管理器上显示的信息一致。

1
2
3
4
5
6
7
8
9
10
#include<windows.h>
#include<stdio.h>
int main() {
SYSTEM_INFO info = { 0 };
GetSystemInfo(&info);
printf("PAGESIZE:%d\n", info.dwPageSize);
MEMORYSTATUSEX MemoryInfo = { sizeof(MEMORYSTATUSEX) };
GlobalMemoryStatusEx(&MemoryInfo);
printf("Memory Status: %d%%\n", MemoryInfo.dwMemoryLoad);
}

运行结果:

剩下的成员

  • ullTotalPhys:实际物理内存量
  • ullAvailPhys:可使用的物理内存量
  • ullTotalPageFile:当前系统已提交的内存限制
  • ullAvailPageFile:当前系统可以提交的最大内存量
  • ullTotalVirtual:调用进程的虚拟空间的用户内存大小
  • ullAvailVirtual:当前用户空间没有提交的内存
  • ullAvailExtendedVirtual:保留,始终为0

还是用以上的方式去获取结构信息,调试查看结构体成员。

GetProcessMemoryInfo

用于获取进程的一个内存信息,用到这个 api 需要包含 Psapi.h。第一个参数为 HANDLE 类型,也就是我们获取的进程的句柄,第二个参数是一个结构体,用于接收返回的信息,第三个参数是该结构体的大小。

  • PeakWorkingSetSize 是该进程创建以来使用的内存大小(peak表示顶峰)。
  • WorkingSetSize 是该进程当前使用的内存大小。

那么我们获取当前进程所使用的内存信息就像下面一样获取。

1
2
PROCESS_MEMORY_COUNTERS psmemCounters;
GetProcessMemoryInfo(GetCurrentProcess(), &psmemCounters, sizeof(PROCESS_MEMORY_COUNTERS));

VirtualAlloc

用于为本进程分配内存。第一个参数为分配内存的地址,填 NULL 表示让操作系统自己分配,第二个参数就是我们要分配的内存的大小,第三个参数是内存的属性,一般我们传入 MEM_COMMIT 即可,它的作用是为指定的保留内存页面分配内存费用(来自内存的总大小和磁盘上的页面文件)该函数还保证当调用者稍后最初访问内存时,内容将为零,除非/直到实际访问虚拟地址,否则不会分配实际的物理页面,第四个参数是内存的保护属性,就是读写执行那些的,实际上它有以下那么多属性

返回值为一个地址指针。

VirtualFree

用于为本进程释放内存,第一个参数为释放内存的起始地址,第二个参数为 size,但是通常情况下我们只有传 0 才能成功释放,传其他值不能够释放。第三个参数我们就给 MEM_REALEASE,表示释放这个内存。

其实释放这个内存的函数,两个参数都是固定的。

关于这个参数的解释可以去看 msdn,有详细说明。

VirtualQuery

查询内存页面的属性,第一个参数为内存地址,第二个参数为接受内存信息的结构体指针,第三个参数为结构体大小。

结构体定义如下

1
2
3
4
5
6
7
8
9
10
11
12
typedef struct _MEMORY_BASIC_INFORMATION {
PVOID BaseAddress;
PVOID AllocationBase;
DWORD AllocationProtect;
#if defined (_WIN64)
WORD PartitionId;
#endif
SIZE_T RegionSize;
DWORD State;
DWORD Protect;
DWORD Type;
} MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;
  • BaseAddress:内存基地址
  • AllocationBase:申请区域的基地址
  • AllocationProtect:内存保护属性,读写执行那些的
  • RegionSize:区域的大小
  • State:页面的状态
  • Protect:区域中页面的访问保护
  • Type:页面类型

VirtualProtect

更改内存页保护属性,第一个参数为该内存页地址,第二个参数为大小,第三个参数为要设置的保护属性,第四个参数用于接收该内存页原属性。

总结

以上 Virtual 开头的 api 均有 Ex 模式, Ex 模式表示在别的线程当中进行对应的操作。不过事先我们要先获取进程句柄,并且 给上 PROCESS_ALL_ACCESS 的权限。

这节课也就是学习了一些内存相关 API 的使用,算打点基础吧,本节课写的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include<windows.h>
#include<stdio.h>
#include<Psapi.h>
int main() {
SYSTEM_INFO info = { 0 };
GetSystemInfo(&info);
printf("PAGESIZE:%d\n", info.dwPageSize);
MEMORYSTATUSEX MemoryInfo = { sizeof(MEMORYSTATUSEX) };
GlobalMemoryStatusEx(&MemoryInfo);
printf("Memory Status: %d%%\n", MemoryInfo.dwMemoryLoad);
PROCESS_MEMORY_COUNTERS psmemCounters;
GetProcessMemoryInfo(GetCurrentProcess(), &psmemCounters, sizeof(PROCESS_MEMORY_COUNTERS));

LPVOID buffer=VirtualAlloc(NULL, 0x1000, MEM_COMMIT, PAGE_READWRITE);
if (buffer == NULL) {
printf("alloc fail");
exit(0);
}
RtlZeroMemory(buffer, 0x1000);
VirtualFree(buffer, 0, MEM_RELEASE);
MEMORY_BASIC_INFORMATION lpbuffer = { 0 };
VirtualQuery(buffer, &lpbuffer, sizeof(MEMORY_BASIC_INFORMATION));
system("pause");
}
文章目录
  1. 1. 课堂笔记
    1. 1.1. WINAPI学习
      1. 1.1.1. GetSystemInfo
      2. 1.1.2. MemoryStatusEx
      3. 1.1.3. GetProcessMemoryInfo
      4. 1.1.4. VirtualAlloc
      5. 1.1.5. VirtualFree
      6. 1.1.6. VirtualQuery
      7. 1.1.7. VirtualProtect
    2. 1.2. 总结
|