• 《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字节。

      

  • 相关阅读:
    微信公众号图片抓取
    ArcGIS Pro SDK开发从别的收集
    ARCGIS Pro试用申请教程以及登录页面脚本错误解决办法
    ArcMap python IndentationError: unexpected indent 莫名的错误解决
    ArcGIS Python更新顺序2种方法
    ArcGIS三维模型
    三维文件格式知多少 | abc、glTF、fbx、obj、dae、stl、3ds
    ArcGIS Pro创建点场景图层包(CreatePointSceneLayerPackage)
    What is the difference between SqlCommand.CommandTimeout and SqlConnection.ConnectionTimeout?
    Reference Microsoft.SqlServer.Smo.dll
  • 原文地址:https://www.cnblogs.com/lihuixian001/p/2890761.html
Copyright © 2020-2023  润新知