虚拟内存和物理内存

来源:互联网 发布:淘宝店上传数据包 编辑:程序博客网 时间:2024/04/27 20:33

作者:cscratch

转自:http://blog.csdn.net/cscratch/article/details/3030905


在现代的操作系统中,当我们说到内存,往往需要分两部分来讲:物理内存和虚拟内存。从硬件上讲,虚拟空间是CPU内部的寻址空间,位于MMU之前,物理空间是总线上的寻址空间,是经过MMU转换之后的空间。

       从逻辑上来讲,虚拟内存和物理内存之间存在着一对一、多对一的映射关系。一对一的关系很好理解,就是有一块物理内存,就有唯一的一块虚拟内存和它对应。但在CE中,这种情况是不存在的。我们知道,0x80000000—0xBFFFFFFF是对所有可用的内存和外设控制器的静态映射,其中低的一半地址是Cacheable的,高的一半地址是Uncacheable的。所谓静态映射,指这部分映射在系统启动时就已经创建了,和通常的动态创建相对应而言。因此,在CE中,每块内存至少映射了两次。

       静态映射的虚拟内存通常只供内核使用,应用程序和驱动如果也需要访问特定的内存(或者是IO),则需要重新分配一块虚拟内存,以映射到目标物理内存。这种情况下,常常使用VirtualAlloc和VirtualCopy:

LPVOID VirtualAlloc(
  LPVOID lpAddress,
  SIZE_T dwSize,
  DWORD flAllocationType,
  DWORD flProtect
);

VirtualAlloc用于分配一片虚拟内存,参数lpAddress用于指定虚拟内存的地址。当lpAddress为空时,系统自动分配一个未用的虚拟地址。(有趣的是,在CE5中,如果lpAddress恰好是32MB(0x2000000)的倍数,则系统在以这个地址为基地址的进程中创建一块虚拟内存,一个后门哦:)如果我们只是需要任意一块内存,在flProtect参数中使用MEM_COMMIT来随即分配一片物理内存。反之,我们使用MEM_RESERVE参数,仅分配一块虚拟内存,然后使用VirtualCopy映射到目标物理内存。

BOOL VirtualCopy( 
  LPVOID lpvDest, 
  LPVOID lpvSrc, 
  DWORD cbSize, 
  DWORD fdwProtect 
);

VirtualCopy的源地址参数lpvSrc可以就是需要访问的物理地址,也可以是已经映射到目标物理地址的一个虚拟地址。目标地址参数lpvDest就是使用VirtualAlloc得到的虚拟内存。顾名思义,Copy以后,程序就可以在自己的进程空间里面访问目标内存了。

       除了上述的映射关系,其实还有两种特别的映射。

       一种是一对零,就是分配了虚拟内存,但是没有对应物理内存。在VirtualAlloc中使用MEM_RESERVE或MEM_AUTOCOMMIT都会出现这种情况。前者是为了接下来使用VirtualCopy手动分配,后者则是一种延迟分配的策略,当读写操作发生时会自动分配。

       还有一种是零对一,就是一块物理内存,但是没有虚拟内存对应。那我们怎么访问呢?通常是DMA。比如某个控制器的FIFO寄存器,如果只需要DMA访问,就可以不映射虚拟内存。再比如从摄像头获得的图像,不经过CPU,直接显示在屏幕上,那么DMA的缓冲区也不需要映射虚拟地址。


原创粉丝点击