个人觉得比较重要的两个概念:
一、每个进程的用户模式地址空间都是独立的私有的,用VS调试时输入的“内存地址”是地址空间值,其对应的真实物理地址对我们是透明的(MMU负责虚拟地址映射为物理地址)。内核模式分区是共有的。应用程序是在用户模式下(Ring 3),驱动为内核模式(Ring 0)。 (Ring 0 权限获取)
二、CPU只能访问内存上的数据。所以当要访问地址空间的一个数据时,要查看这个数据是否在内存上,不在则需要从页交互文件中复制到内存上。(核心编程上有流程图)。
---------------------------------------------------------------------------------------------------------------------
进程的虚拟地址空间间分为四个部分:空指针赋值分区,用户模式分区(对用户可用),64KB禁入分区,内核模式分区。
1.虚拟内存查询就几个函数调用。有个NUMA(非统一内存访问)机器,没怎么看。
2.VirtuaAlloc:
默认是从“页交互文件”中调拨物理存储器。
大页面支持(MEM_LARGE_PAGE)和AWE(MEM_PHYSICAL)是从“物理内存”
3.线程栈:
默认1MB(有人说跟编译器和系统有关,我32位WIN7,VS2010上是1MB),并在高地址调拨两个页面。有个防护属性对栈满保护。书上栈下溢的代码有点问题补上:(但对于栈后内存已预定区域的读写属性改不过来,不知道为啥~没权限?)
void CsixteenDlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
BYTE aBytes[0x10]={"1234567"};
//Figure out where the stack is in the virtual address space
MEMORY_BASIC_INFORMATION mbi;
SIZE_T size = VirtualQuery(aBytes,&mbi,sizeof(mbi));
//Allocate a block of memory just after the 1MB stack
SIZE_T s = (SIZE_T)mbi.AllocationBase + 1024 *1024;
PBYTE pAddress = (PBYTE)s;
SIZE_T interval = s - (SIZE_T)aBytes;
size = VirtualQuery(pAddress,&mbi,sizeof(mbi));
BYTE * pBytes = NULL;
DWORD dOldProtect = 0;
if(mbi.State == MEM_COMMIT)
{
::OutputDebugStringA("线程栈后地址空间已经预定\r\n");
if(mbi.Protect != PAGE_READWRITE)
{
//修改页保护属性不能跨区域,要分多次调用
//改变线程栈后一个页面的保护属性
if(!VirtualProtect(pAddress,2*1024,PAGE_READWRITE,&dOldProtect))
{
::OutputDebugStringA("修改页保护属性为可读可写失败\r\n");
return;
}
}
}
else
{
pBytes = (BYTE *)VirtualAlloc(pAddress,0x10,MEM_COMMIT| MEM_RESERVE, PAGE_READWRITE);
}
//Trigger an unnoticeable stack underflow
aBytes[interval] = 1; //Write in the allocated block,past the stack
//还原保护属性
if(dOldProtect != 0)
{
DWORD temp =0;
VirtualProtect(pAddress,4*1024,dOldProtect,&temp);
}
//释放地址空间
if(pBytes != NULL)
{
VirtualFree(pAddress,0,MEM_RELEASE);
}
}
4.内存映射文件:
要提到“写时复制”:多实例运行,对于需要写时复制保护的页面会在页交换文件挑拨存储器,但只有在一个实例真正写入其中一个页面时才使用到。个人觉得“写时复制”就是保护数据的独立性。
作用:进程间通信,创建自定义段,#pragma comment(linker,"/SECTION:Shared,RWS")设置共享。
大文件操作
5.堆:
自定义堆的好处:对组件进行保护(一个结构处理代码有缺陷可能会覆盖掉另一个结构的内容区),
更有效的内存管理,使内存访问局部化(减少内存与磁盘之间的交换),避免线程同步的开销,快速释放。
另外:页保护属性是针对页的。可以用来保护数据,定位一个很难发现的缺陷(谁来举个例子加深下印象)
最后给个图: