本文主要是介绍windows 虚拟内存,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
一、虚拟内存
1、内存分页的概念:
内存分页是一种将物理内存划分成固定大小的块,并将虚拟内存映射到这些物理内存块的技术。在内存分页的实现中,每个物理内存块被称为一个页框,每个虚拟内存块被称为一个页面。操作系统将虚拟地址空间划分为固定大小的页面,并将其映射到物理地址空间中的页面框中。
内存分页的主要目的是实现虚拟内存,以提高系统的内存利用率。由于虚拟内存允许将页面换入换出到磁盘上,因此在物理内存不足时,可以将不常用的页面换出到磁盘上,从而释放物理内存,并为正在执行的进程提供足够的内存空间。同时,内存分页还可以使操作系统更加灵活地管理内存,以便实现内存保护和共享等功能。
在内存分页的实现中,操作系统通常会将每个页面映射到一个页表项中。页表项包含了虚拟页面的地址、页面的状态信息、页面的访问权限、页面所属的进程等信息。当CPU访问一个虚拟地址时,操作系统会根据该地址对应的页表项,将虚拟地址映射到物理地址,并检查对应的页面是否已经在物理内存中。如果页面不在物理内存中,操作系统就会触发一个缺页异常,将页面从磁盘上读取到物理内存中,并更新页表项。
内存分页是一种将虚拟内存映射到物理内存的技术,它实现了虚拟内存和内存保护等功能,提高了系统的内存利用率,并为操作系统提供了更加灵活的内存管理手段。
2、操作系统分页概述:
操作系统如何管理内存?
作系统管理内存是将内存分成一页一页来管理的,每一页的大小是4K也就是0x1000
4G的内存共有1M个页。
使用了分页机制之后,4G的地址空间被分成了固定大小的页,每一页或者被映射到物理内存,或者被映射到硬盘上的交换文件中,或者没有映射任何东西。对于一般程序来说,4G的地址空间,只有一小部分映射了物理内存,大片大片的部分是没有映射任何东西。CPU用来把虚拟地址转换成物理地址的信息存放在叫做页目录和页表的结构里。
3、虚拟内存状态:
状态 | |
空闲(FREE) | 内存页不可用 |
保留(Reserve) | 内存页被预定了,但为与物理内存做映射,还是不可用 |
提交(Commit) | 内存被分配,并且与物理内存进行了映射,进程可以使用了 |
当虚拟内存映射到物理内存时,有三种映射方式
4、内存映射方式:
映射方式 | 描述 |
Private | 进程私有内存,不被其他进程所共享,一般是堆,栈 |
Mapped | 从别的内存映射而来 |
Image | 从程序的PE映像映射而来。 |
虚拟内存管理-内存属性:
Windows中,内存管理的最小单元是一个内存页 通常是0x1000=4kb
5、内存分页属性:
ReadOnly | 只读 |
READ_WRITE | 读写 |
EXECUTE | 执行 |
EXECUTE_READ_WRITE | 可读可写可执行 |
WRITE_COPY | 写时拷贝 |
6、页交换文件逻辑:
程序访问虚拟内存地址,操作系统判断数据是否在内存中,如果在就从虚拟地址映射到的物理地址,如果不在就判断是否在页交换文件当中,如果在就查看物理内存是否有闲置空间,有的话,就将页交换文件载入到物理内存,如果没有闲置内存,就从物理内存中找到一个可以释放的页,然后将页保存到页交换文件中。
7、虚拟内存相关API :
VirtualAlloc | 分配或者预定一块虚拟内存 |
VirtualAllocEx | 可以在其他进程分配或者预定一块内存 |
VirtualFree | 释放内存 |
VirtualFreeEx | 可以释放其他进程内存 |
VirtualLock | 锁定内存不能交换到硬盘 |
VirtualUnLock | 解锁 |
VirtualProtect | 修改内存读写执行属性 |
VirtualProtectEx | 可以修改其他进程内存属性 |
ReadProcessMemory | 读取远程进程内存 |
WriteProcessMemory | 写入数据到远程进程内存 |
VirtualQuery | 查询内存状态 |
8、虚拟内存案例
下面我们利用虚拟内存的特点来修改C++当中的常量:没错!就是那些你以为不可能被改动的const char*那些玩意
#include <iostream>
#include<Windows.h>
#include<cstring>
int main()
{
const char* str = "码农今天在好好摆烂!\n";
std::cout << "字符串常量修改前:" << str << std::endl;
// 获取字符串所在内存区域的地址
const void* addr = static_cast<const void*>(str);
// 修改内存保护属性为可写属性
//记得保存一下内存区域的原有访问属性,以便后续恢复他的属性,避免报错
DWORD old_protect;
VirtualProtect((char*)addr, strlen(str), PAGE_EXECUTE_READWRITE, &old_protect);
// 修改字符串内容
char* writable_str = const_cast<char*>(str);
char* index = std::strstr(writable_str, "摆烂");
if (index != nullptr) {
std::memcpy(index, "学习!\0", 7);
}
// 输出修改后的字符串内容
std::cout << "字符串常量修改后:" << str << std::endl;
// 恢复内存保护属性为只读属性
VirtualProtect((char*)addr, strlen(str), old_protect, &old_protect);
return 0;
}
这篇关于windows 虚拟内存的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!