Windows内存构架

Windows内存构架
1.进程虚拟地址空间
     每个进程都有自已的私有的虚拟地址空间,在32位机器上是4G,在64位机器上是16EB
     进程内的线程只能访问其所属进程所占的内存,其它进程的内存对其而言是不可见的,无法访问到。
2.虚拟地址空间是如何划分的
     32 x86进程的虚拟地址被分成四个区域(Partition)
    (1)空指针区域 0x00000000 ~ 0x0000FFFF
      专门留出来帮助程序员捕获空指针操作,如果线程试图读、写该区域所占的内存会导致进程异常退出。
   (2)用户模式区域 0x00010000 ~ 0x7FFEFFFF (2G)
       任何进程都不可读、写其它进程在该区域存放的数据。
       所有的DLLEXE文件都会加载到该区
       通过控制BCD可以增加用户模式区哉的范围,详见:
   (3)内核模式区域 0x80000000 ~ 0xFFFFFFFF
        操作系统的代码存放在这里,如线程、内存管理、文件系统支持、网络支持、设备驱动。
        该区存放的所有东西被所有进程共享。
        该区存放的代码和数据会被保护起来,应用程序若试图读、写该区的内存会导致异常退出,除非应用
程序的线程则用户模式切换到内核模式。
    (4)64KB禁上入内区域 0x7FFF0000 ~ 0x7FFFFFFF
3.地址空间内的区域
    VirtualAlloc该函数的功能是在调用进程的虚地址空间,预定或者提交一部分页。
        根据CPU不同,VirtualAlloc分配的粒度也不同,但一般都是以64K为基本单位。
        不同CPU分页大小也不同,X86X64分页大小是4K
   (1)保留地址空间 Reserve address space
           保留地址空间:在进程地址空间中保留出一块地址空间也备后用。因为这块地址空间并没有实际的存储映射,所以若访问这块内存会导致进程异常退出。
VOID GetSystemInfo(LPSYSTEM_INFO psi);取得系统分页大小、内存分配粒度(Allocation Granularity)
      在保留地址空间时有两点限制:
          1.被保留地址空间的首地址必须以内存分配粒度为边界(地址的值可以整除内存分配粒度的值)
          2.被保留地址空间的大小必须是页大小的整数倍,若不是整数倍系统会自动对齐到整数倍。
      例如,页大小为4K,若要保留10KB大小的空间,系统会自动对齐,保留12K(4*3)大小的空间
   (2)提交物理存储到保留的地址空间
      物理存储包括:物理内存和用做虚拟内存的页文件。
      物理存储总是以分页大小为基本单位提交的。
­
4.物理内存和页文件
  物理内存(RAM):内存硬件的实际存储容量
  虚拟内存:用于当做内存来弥补计算机RAM空间缺乏的硬盘空间。当实际RAM满时(实际上,在RAM满之前),虚拟内存就在硬盘上创建了。当物理内存用完后,虚拟内存管理器选择最近没有用过的,低优先级的内存部分写到交换文件上。这个过程对应用是隐藏的,应用程序把虚拟内存和实际内存看作是一样的。虚拟内存大小是由系统的页文件(Paging file)限制的。
5.数据对齐
如果一个变量的地址可以整除该变量所占内存大小,那么就称该变量是数据对齐的。
DWORD的大小是4 若其地址为0x00000004 那么它就是数据对齐的。
­
7.Copy-On-Write
     一个应用程序的多个实例在运行时共享代码段或数据段。但某个实例修改全局或静态变量时,系统会以Copy-on-write的方式修改全局变量。即,系统会新建一个页,然后所要修改的全局变量所在的页的内容拷贝到新的页上,再在新的修改全局变量。
8.系统信息
    用虚拟内存编程时需要用到一些系统的一些信息,如分页大小,分配粒度大小等等。
     为了避免将这此信息Hard Code到代码中,使程序具有更好的移植性,我们可能通过调用下面的方法获取我们需要的信息。
              VOID GetSystemInfo(LPSYSTEM_INFO psi);
9.Common API
              VirtualAlloc             VirtualFree
              VirtualQuery
­
应用虚拟内存
1.在地址空间内保留一块区域(地址空间)
   LPVOID WINAPI VirtualAlloc(
      __in   LPVOID lpAddress,//指定区域的首地址 (地址值为64KB的整数倍)
      __in   SIZE_T dwSize,    //区域的大小(字节数) 4KB的整数倍
      __in   DWORD flAllocationType,//分配方式:Reserve|Commit|Reset MEM_TOP_DOWN|MEM_LARGE_PAGES
      __in   DWORD flProtect //设置保护属性
    );
     (1)lpAddressNULL, 系统会在进程空间中找到一块合适区域,然后将该区域的地址返回
     (2)若想指定区域的首地址, 则需将首地址的值赋给lpAddress
     系统会自动将该值切割成64KB的整数倍,如:我们想在19,668,992 (300 × 65,536 + 8192)处保留一块区域
系统会把19,668,992切割成19,660,800 (300 × 65,536). 然后在该地址处保留一块区域并返回该值(19,660,800)
     (3) MEM_TOP_DOWN 在高地址处分配空间
         lpAddressNULL,系统可能在进程空间的任意部分保留一块区域。若该区域是在进程的地址空间的中部,则有可能会产生内存碎片。
         为了避免内存碎片的产生 尤其是当我们想常时间保留一块区域时,我们可以通过设定MEM_TOP_DOWN,让系统尽可能的在高地址处保留一块区域。
2.交付会把实际的物理存储空间分配给保留的区域。
   我们可以在保留一块区域的同时来交付这块区域。也可以先保留,等需要时再交付这块区域。
   当需要分配大量内存时,如果CPU支持“大分页分配”,可以用MEM_LARGE_PAGE GetLargePageMinimum来增加分页大小,提高分配内存的性能。
   在做大分布分配时有以下两点需要注意:
      (1)大分页分配的内存是unpageable的,只能存在于RAM中,不会存在Page file
      (2)用户必而具有Lock Memory的权限。
更多信息查阅MSDN by keyword:Large Page Support
3.何时交付内存
    适时的交付内存可以提高内存的使用效率,避免分配不必要的内存导致内存资源浪费。
    判断何时分配内存的最好方法是SHE(Structured Exception Handling),详见第二十五章
4.解除交付和释放保留区域
   Decommitting Physical Storage and Releasing a Region
   BOOL VirtualFree(
     LPVOID pvAddress,
     SIZE_T dwSize,
     DWORD fdwFreeType
    );
(1)释放保留区域 release a region
    当释放保留区域时,我们必须释放整个保留的区域,该交付给该区域会被释放掉。试图访问已释放的区域会导致异常。
(2)解除交付
    仅释放内存,但该区域仍处于保留状态。我们可以仅解除一部分区域而不必像“释放保留区域”那样解除整个区域
    解除交付也是以分页为单位的。dwSize指定了要释放的大小(以字节为单位)
    若大小不够一页按一页算。例:3KB,那么系统会解除交付 pvAddress~pvAddress+4KB空间内的内存。5KB,那么系统会解除交付 pvAddress~pvAddress+8KB空间内的内存。
5改变保护属性
    BOOL VirtualProtect(
        PVOID pvAddress,
        SIZE_T dwSize,
        DWORD flNewProtect,
        PDWORD pflOldProtect
     );
我们在保留地址空间时要指定区域的保护的属性。
通过VirtualProtect函数我们可以动态地改变区域中某些分页的保护属性
6.Reset物理存储的内容
    Reset的用途是告诉系统指定的区域的内容没有改变,不需要将该区域的内容写到页文件中。
    以便使这块区域长期存放在RAM,以便再用到该区域时不需要换页操作。
posted @ 2009-06-17 10:41  辛勤耕耘  阅读(486)  评论(0)    收藏  举报