《Windows核心编程第五版》笔记

第13章 Windows内存体系结构

【NOTE】进程的虚拟地址空间

   32位进程的地址空间的大小是4GB

 

【NOTE】虚拟空间地址的分区 (x86 32位)

1.空指针赋值分区  0x00000000~0x0000FFFF (0~65,535     65536大小)

  *我们没有办法分配到这分区地址来使用

参考这里
原文地址:http://www.cnblogs.com/anzhihun/archive/2009/08/08/1349032.html

1.为什么通过空指针读写的时候就会出现异常?
2.除了NULL表示空指针,是否还有其他的值也是空指针?
3.如果还有其他的值,你们这些表示空指针的值都是什么?为什么?

首先解答第一个问题,在windows核心编程第四版的windows的内存结构一章中,表13-1有提到NULL指针分配的分区。其范围是从0x00000000到0x0000FFFF。这段空间是空闲的,对于空闲的空间而言,没有相应的物理存储器与之相对应,所以对这段空间来说,任何读写操作都是会引起异常的。

有了上面的解答后,第二个问题就很容易解答了。NULL的定义出现以下几个地方:

stdio.h文件中

#ifndef NULL 
#ifdef  __cplusplus 
#define NULL    0 
#else 
#define NULL    ((void *)0) 
#endif 
#endif

ios.h文件中

#ifndef NULL 
#define NULL    0 
#endif

windef.h文件中

#ifndef NULL 
#ifdef __cplusplus 
#define NULL    0 
#else 
#define NULL    ((void *)0) 
#endif 
#endif

可见,NULL的值,基本上是用0来表示的,是不是只能用0呢?在windows xp sp2的系统平台下,如果执行下面代码也是会发生异常的:

int * pAddr = (int *)0x0000ffff;

*pAddr = 1;

而下面的代码是不会出问题的:

int * pAddr = (int *)0x00010000;

*pAddr = 1;

为什么呢?在windows xp sp2下发现0x00000000到0x0000FFFF是空闲区间,而0x00010000所处的是进程的私有区间。我想第二个问题应该已经解决了,我想,空指针是程序无论在何时都没有物理存储器与之对应的地址。为了保障“无论何时”这个条件,需要人为划分一个空指针的区域,固有上面NULL指针分区。

在第二个问题的基础上,要解答NULL指针的范围,那就相对来说容易了,对于在32位x86计算机上运行的windows xp sp2来说,就是从0x00000000到0x0000ffff。为什么分配如此大的空间?而在定义NULL的时候,只使用了 0x00000000这么一个值,这不是浪费吗?我想,这是操作系统地址空间的分配粒度相关的,windows xp sp2的分配粒度是64KB,为了达到对齐,空间地址需要从0x00010000开始分配,故空指针的区间范围有那么大。

上面的阐述如有问题,希望各位更正,谢谢。

 2.用户模式分区

x86   0x0010000~0x7FFEFFFF  65,535~2,147,418,111

* 进程不能通过指针访问驻留在这分区的其他进程的数据

3.64KB禁入分区

4.内核模式分区

x86 0x80000000~0xFFFFFFFF  2,147,483,648~4,294967,295

 

【NOTE】地址空间中的区域

* 预定(reserving)与调拨(committing)

* 预定地址空间区域时,区域的起始地址的分配粒度是64KB,大小的分配粒度正好是页面大小4KB

 

 【NOTE】物理存储器和页交换文件

* VirtualAlloc函数调拨的一般是页交换文件,不是内存的物理空间

* 当一个线程试图访问所属进程的地址空间的一块数据的时候:

  情况1:要访问的数据就在内存中,此时CPU先把虚拟内存地址映射到内存的物理地址上,接下来就可以访问了

  情况2:要访问的数据在页交换文件中,此时CPU将页面错误通知操作系统,操作系统随即在内存中寻找一个闲置的页面。如果找不到,就必须释放一个已分配页面,如果待释放的页面没有被使用过,就可以直接被释放。如果被使用过,操作系统就必须先把页面复制到交换文件中,再释放。

 

【NOTE】内存映射文件---不在页交换文件中维护的物理存储器(物理存储器可以在内存条或者页交换文件中)

* 当载入一个dll/.exe时,系统会计算应用程序的代码和数据大小,然后预定一块地址空间,并且注明关联的物理存储器就是dll/.exe本身,从而不用另外关联页交换文件,从而避免了在硬盘中的复制

 

【页面保护属性】

* 页面保护属性一览:

  PAGE_NOACCESS

  PAGE_READONLY

  PAGE_READWRITE

  PAGE_EXECUTE

  PAGE_EXECUTE_READ

  PAGE_EXECUTE_READWRITE

  PAGE_WRITECOPY

  PAGE_EXECUTE_WRITECOPY

 

* 对内存的操作有:读取,写入,执行代码, 页面属性保护就是针对上述操作进行保护

 

* 进程虚拟地址空间中每个区域可能是以下四种类型之一:

    1.闲置,表示还没有被预订。

    2.私有,表示虚拟地址以页交换文件作为后备存储器。

    3.映像,表示虚拟地址以映像文件(比如.EXE或者.DLL)为后备存储器。

    4.已映射,以内存映射文件为后备存储器。

 

【NOTE】写时复制

* PAGE_WRITECOPY 、PAGE_EXECUTE_WRITECOPY

*  Windows的一个机制,允许多个进程共享一个存储器,如果可以同时有10个记事本程序同时运行,这就要求所有的实例只能读取和执行里面的代码

* 预定地址空间和调拨物理存储器的时候不能使用PAGE_WRITECOPY 、PAGE_EXECUTE_WRITECOPY两个属性,这两个属性是系统映射dll/.exe映像文件的时候用的

 

【NOTE】数据对齐--数据的地址模除数据自的大小等于0

* 对齐步骤:

  1.结构体的对齐规则是先按数据类型自身进行对齐

  2.然后再按整个结构体进行对齐

  例子:

struct Test1
{
    int i ;
    double d ;
    char c ;
};

  4(i) + 4(补齐)+ 8(d) + 1(c) =  17字节  ,然后整体以最大的类型double对齐,所以整体以8对齐,17 + 7(补齐) = 24字节。

 

 

 

 

 

  

 

 

posted @ 2013-02-04 20:11  杂草  阅读(525)  评论(0编辑  收藏  举报