系统调拨物理存储器(磁盘中的页交换文件和文件映像)给进程的数据与程序,把地址映射到进程地址空间。
一开始进程所有页面都在磁盘上,内存中没有数据与程序,所以要先从它们的物理存储器中调入内存。
让磁盘空间看起来像内存一样,这部分磁盘空间称为页交换文件。
页交换文件在硬盘上,一种内存的后备存储器。把页交换文件映射到进程地址空间。
1.预定地址空间区域
PVOID VirtualAlloc(
PVOID pvAddress,
SIZE_T dwSize,
DWORD fdwAllocationType,
DWORD fdwProtect); fdwAllocationType设置为MEM_RESERVE
2.调拨物理存储器(页交换文件)
fdwAllocationType设置为MEM_COMMIT
3.撤销调拨物理存储器及释放区域
BOOL VirtualFree(
LPVOID pvAddress,
SIZE_T dwSize,
DWORD fdwFreeType);
系统创建线程时,会给线程栈预订一块地址空间区域,并调拨页交换文件(大小由.exe的PE文件头中变量指定)。
文件映像(.exe文件或DLL),另一种后备存储器,称之为内存映射文件,映射到进程地址空间。
硬盘上的文件映射在进程的地址空间中。
1.创建或打开文件,创建文件内核对象
HANDLE CreateFile(
PCSTR pszFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
PSECURITY_ATTRIBUTES psa,
DWORD dwCreationDisposition,
DWORD dwFlagsAndAttributes,
HANDLE hTemplateFile); 2.创建内存映射文件内核对象
HANDLE CreateFileMapping(
HANDLE hFile,
PSECURITY_ATTRIBUTES psa,
DWORD fdwProtect,
DWORD dwMaximumSizeHigh,
DWORD dwMaximumSizeLow,
PCTSTR pszName);
3.映射到进程地址空间,在地址空间中预订区域并调拨物理存储器
PVOID MapViewOfFile(
HANDLE hFileMappingObject,
DWORD dwDesiredAccess,
DWORD dwFileOffSetHigh,
DWORD dwFileOffSetLow,
SIZE_T dwNumberOfBytesToMap);
告诉编译器把变量放入单独的段中
#pragma data_seg("shared")
#pragma data_set()
#pragma comment(linker, "/SECTION:Shared,RWS")
####用内存映射文件在进程间共享数据
当启动一个应用程序,系统会先调用CreateFile打开.exe文件,接着调用CreateFileMapping创建文件映射对象,最后调用MapViewOfFileEx映射到进程的固定地址空间(有.exe的PE文件指定基地址)。打开同一个应用程序,系统发现已经存在文件映射对象,就调用MapViewOfFileEx映射.exe文件到对应进程的地址空间。所以系统把相同文件映射到不同进程中,令进程共享程序的代码与数据。
####以页交换文件为后备存储器的内存映射文件
不再以磁盘文件作为后备存储器,则不需要打开文件创建文件内核对象,直接创建内存映射文件对象,把页交换文件映射到内存。
多进程可以利用页交换文件的内存映射文件来共享数据。利用对映射文件对象取别名来标记对象。
###堆
进程创建的时候,系统会分配一个默认堆。
调拨的物理存储器来自页交换文件。
####创建额外堆
HeapCreate(
DWORD fdwOptions,
SIZE_T dwInitialSize,
SIZE_T dwMaximumSize);
不能保证线程独占堆则不能设置fdwOptions为HEAP_NO_SERIALIZE,保证多线程对同一个堆的访问时依次进行。
####从堆中分配内存
PVOID HeapAlloc(
HANDLE hHeap,
DWORD fdwFlags,
SIZE_T dwBytes);