虚拟内存实现的硬件基础是分页机制,关于分页机制本文再此不做介绍。虚拟内存实现的另外一个重要基础是局部性原理。局部性是指程序总是趋向于使用最近使用过的数据和指令,也就是说程序执行时所访问的存储器地址分布是相对集中的。局部性原理是应用虚拟内存提升性能的主要原因,也是虚拟内存却别与内存映射文件的本质。
内存映射文件虚拟性并不是由于局部性,而是使进程虚拟地址空间的某个区域建立映射磁盘文件的全部或部分内容,通过该区域可以直接对被映射的磁盘文件进行访问,而不必执行文件I/O操作也无需对文件内容进行缓冲处理。
内存映射文件
1.载入并运行exe和dll.
2.访问磁盘的数据文件,而不必执行文件I/O操作。
3.不同进程之间共享数据。
映射到内存的可执行文件和dll
1.调用createprocess,确定可执行文件的位置
2.系统创建一个新的进程内核对象‘
3.系统为新进程创建一个新的地址空间
4.系统预定足够大的地址空间容纳exe文件,
5.系统对地址空间标注,表明该区域是来自磁盘的exe文件,而不是系统的页交换文件。
当exe文件映射到进程的地址空间后,后调用loadlibrary函数载入dll.同时dll和上面步骤4,5一样。
在exe或dll文件中,代码段通常在数据段前面。使用编译器编译的时候
.bss 未经初始化的数据
.data 已初始化的数据
.text exe或dll 的代码
此外可以使用编译器自定义段
#pragma data_seg ("DLLSharedSection ")
int i = 0; //必须要初始化
#prama data_seg()
链接器的工作
仅定义一个数据段还不能达到共享数据的目的,还要告诉编译器该段的属性,有三 种方法可以实现该目的(其效果是相同的), |
一种方法是在.DEF文件中加入如下语句:SETCTIONS DLLSharedSection READ WRITE SHARED |
另一种方法是在项目设置的链接选项(Project Setting --〉Link)中加入如下语句: /SECTION:DLLSharedSection,rws |
还有一种就是使用指令: #pragma comment(linker,"/section:.DLLSharedSection,rws") |
文件映射内核对象
1.创建文件内核对象,调用createfile.目的是为了告诉系统文件映射的物理存储器的位置。
1 2 3 4 5 6 7 8 |
|
2.创建文件映射内核对象 ,调用createfilemapping.目的就是系统需要多少的物理存储器。
2 3 4 5 6 7 |
|
hFile:Long,指定欲在其中创建映射的一个文件句柄。0xFFFFFFFF(-1,即INVALID_HANDLE_VALUE)表示在页面文件中创建一个可共享的文件映射,表明创建的文件映射对象的物理存储器不是磁盘的文件,而是系统从页交换文件中调拨物理存储器。即在磁盘c的pagefile.sys文件,因此不需要再调用createfile函数。
lpFileMappigAttributes:如果为NULL,表示使用默认安全对象
flProtect:可以是PAGE_READWRITE PAGE_READONLY PAGE_WRITE 等 但这些参数必须跟createfile的变量dwDesiredAccess对应起来。
dwMaximumSizeHigh:Long,文件映射的最大长度的高32位。在小于4G ,该值为0
dwMaximumSizeLow:Long,文件映射的最大长度的低32位。
如果想要用当前文件的大小创建一个文件映射对象,只要传0给两个参数就可以。
如果传入的是page_readwrite,如果文件大小比指定的要小,则会增大文件的大小。
如果使用的是page_readonly或page_writecopy,指定的大小不能大于文件的大小。
lpName:以0为终止符的字符串,这个名词可以实现不同的进程间共享内存。
在该createfilemapping过程中,系统不会预订一块地址空间区域并将文件映射到该区域中。
3.将文件的数据映射到进程的地址空间,调用mapviewoffile
LPVOID WINAPI MapViewOfFile(
__in HANDLE hFileMappingObject,
__in DWORD dwDesiredAccess,
__in DWORD dwFileOffsetHigh,
__in DWORD dwFileOffsetLow,
__in SIZE_T dwNumberOfBytesToMap
);
hFileMappingObject 为CreateFileMapping()返回的文件映像对象句柄。
dwDesiredAccess 映射对象的文件数据的访问方式,而且同样要与CreateFileMapping()函数所设置的保护属性相匹配。 可取以下值flProtect FILE_MAP_WRITE FILE_MAP_READ FILE_MAP_ALL_ACCESS 等
dwFileOffsetHigh 表示文件映射起始偏移的高32位. 一般是0
dwFileOffsetLow 表示文件映射起始偏移的低32位.(64KB对齐不是必须的) 一般是0
dwNumberOfBytes 指定映射文件的字节数. 如果是0 ,表示文件都映射到地址空间中。同时该变量也意味着只映射部分文件映射文件到进程的地址空间。
如果成功,则返回映射视图文件的开始地址值
该函数是内核对象,符合跨进程共享数据的特性。
作用就是:
为文件的数据预订一块地址空间区域并将文件的数据作为物理存储器调拨给区域。
4.从进程的地址空间撤销文件数据的映射,调用unmapviewoffile,释放进程地址空间。
BOOL WINAPI UnmapViewOfFile(_In_LPCVOID lpBaseAddress);
lpBaseAddress Long,指定要解除映射的一个文件映射的基准地址。这个地址是早先用MapViewOfFile函数获得的
在调用mapviewoffile后,必须调用
UnmapViewOfFile进行撤销映射。因为如果不调用UnmapViewOfFile,那么载调用
mapviewoffile的时候,系统会在进程的地址空间预订一块新的区域,不会释放先前预订的。
5.关闭文件映射对象,调用closehandle
6.关闭文件对象,调用closehandle
特点:
1,系统允许同一文件的数据映射到多进程的多个视图。视图的数据保持一致性,如果一个视图修改内容,其他视图也更新。
2.一个进程调用mapviewoffile,系统在进程地址空间预订的区域,其他进程是看不到这个视图的。另一个进程调用mapviewoffile,是在第二个进程的地址空间预订另一个区域。
3.此外,两个进程调用mapviewoffile的返回值基地址很可能不一样。