虚拟内存
每个进程都有4GB的虚拟内存运行空间
内存分页的概念:
操作系统管理内存是将内存分成一页一页来管理,每一页的大小是4K,也就是0x1000,4G的内存共有1M页
使用了分页机制之后,4G的地址空间被分成了固定大小的页,每一页或者被映射到物理内存,或者被映射到硬盘上的交换文件中,或者没有映射任何东西。对于一般程序来说,4G的地址空间,只有一小部分映射了物理内存,大片大片的部分是没有映射任何东西。CPU用来把虚拟地址转换成物理地址的信息存放在叫做页目录和页表的结构里。
虚拟内存状态
状态 | |
---|---|
空闲(free) | 内存页不可用 |
保留(Reserve) | 内存页被预定了,但还未做物理内存做映射,还是不可以 |
提交(Commit) | 内存被分配,并且与物理内存进行了映射,进程可以使用了 |
内存映射方式
Private | 进程私有内存,不被其他进程所共享,一般是堆、栈 |
---|---|
Mapped | 从别的内存映射过来 |
Image | 从程序的PE映像映射过来 |
内存属性
在Windows中,内存管理的最小单元是一个内存页,通常是0x1000=4kb
PAGE_ReadOnly | 只读 |
---|---|
PAGE_READ_WRITE | 只写 |
PAGE_EXECUTE | 执行 |
PAGE_EXECUTE_READ_WRITE | 可读可写可执行 |
PAGE_WRITE_COPY | 写时拷贝 |
页交换文件逻辑
操作系统会把进程中不常用的东西存到交换文件里面,当操作系统需要读取里面的内容时,就需要用到了页交换逻辑
当程序访问虚拟内存地址,操作系统判断数据是否在内存中,如果在就从虚拟地址映射到对应的物理地址,如果不在就判断是否在页交换文件当中,如果有就看物理内存有没有空闲的地址,有就加入进去然后映射虚拟地址,没有就移出不常用的物理地址内容再填入然后映射,如果都没有就报错。
虚拟内存相关API
VirtualAlloc | 分配或者预定一块虚拟内存 |
---|---|
VirtualAllocEx | 可以在其他进程分配或者预定一块内存 |
VirtualFree | 释放内存 |
VirtualFreeEx | 可以释放其他进程内存 |
VirtualLock | 锁定内存不能交换到硬盘 |
VirtualUnlock | 解锁 |
VirtualProtect | 修改内存读写执行属性 |
VirtualProtectEx | 可以修改其他进程内存属性 |
ReadProcessMemory | 读取远程进程内存 |
WriteProcessMemory | 写入数据到远程进程内存 |
VirtualQuery | 查询内存状态 |
VirtualQueryEx |
VirtualAlloc
LPVOID VirtualAlloc(
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flAllocationType,
DWORD flProtect
);
参数
lpAddress: 要分配的区域的起始地址,如果为0,表示系统自动指定一个地址
dwSize: 要申请的内存大小,会按照页大小对齐
flAllocationType: 内存的状态
flProtect: 内存的属性
//例子
char *test = (char*) VirtualAlloc(0, 1, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
VirtualFree
BOOL VirtualFree(
LPVOID lpAddress,
SIZE_T dwSize,
DWORD dwFreeType
);
参数
lpAddress: 要释放的内存的首地址
dwSize: 要释放的内存的大小,如果为0就全释放
dwFreeType: MEM_DECOMMIT释放后处于保留状态,MEM_RELEASE释放后处于空闲状态
//例子
VirtualFree(test,0, MEM_RELEASE);
VirtualProtect
BOOL VirtualProtect(
LPVOID lpAddress,
SIZE_T dwSize,
DWORD flNewProtect,
PDWORD lpflOldProtect
);
修改内存的属性
参数
lpAddress: 内存的地址
dwSize: 大小
flNewProtect: 新的属性
lpFloldProtect: 获得旧的属性,是一个返回值
//例子
char name[] = "Sna1lGo";
char* cname = (char*)"Sna1lGo";
name[1] = '2';
DWORD oldProtect = 0;
VirtualProtect(cname, 7, PAGE_READWRITE, &oldProtect);
cname[1] = '2';
cout << cname << endl;