关于“内存映射文件”讨论

ljlln 2005-07-07 09:21:04
1、CreateFileMapping 函数到底干了些什么工作?
个人理解:创建一个内存映射文件对象,并保留一个大小和CreateFileMapping中参数指定得地址空间。
2、MapViewOfFile 函数到底干了些什么工作?
个人理解:将内存映射文件对象映射到当前进程得地址空间,设置相关属性,返回数据得基址。
疑问:a、磁盘上文件是否已经加载到内存了?
b、如何理解从基址中读取数据?可以认为从磁盘上读取吗?
3、内存映射文件真的把磁盘上的文件加载到内存了吗?为什么有的书上说,此时读取数据不再进行IO操作?
我想不通。
望大侠赐教 谢谢 。
...全文
522 33 打赏 收藏 转发到动态 举报
写回复
用AI写文章
33 条回复
切换为时间正序
请发表友善的回复…
发表回复
会思考的草 2005-07-18
  • 打赏
  • 举报
回复
HANDLE
APIENTRY
OpenFileMappingA(
DWORD dwDesiredAccess,
BOOL bInheritHandle,
LPCSTR lpName
)

/*++

Routine Description:

ANSI thunk to OpenFileMappingW

--*/

{
PUNICODE_STRING Unicode;
ANSI_STRING AnsiString;
NTSTATUS Status;

if ( ARGUMENT_PRESENT(lpName) ) {
Unicode = &NtCurrentTeb()->StaticUnicodeString;
RtlInitAnsiString(&AnsiString,lpName);
Status = RtlAnsiStringToUnicodeString(Unicode,&AnsiString,FALSE);
if ( !NT_SUCCESS(Status) ) {
if ( Status == STATUS_BUFFER_OVERFLOW ) {
SetLastError(ERROR_FILENAME_EXCED_RANGE);
}
else {
BaseSetLastNTError(Status);
}
return NULL;
}
}
else {
BaseSetLastNTError(STATUS_INVALID_PARAMETER);
return NULL;
}

return OpenFileMappingW(
dwDesiredAccess,
bInheritHandle,
(LPCWSTR)Unicode->Buffer
);
}
会思考的草 2005-07-18
  • 打赏
  • 举报
回复
HANDLE
APIENTRY
CreateFileMappingW(
HANDLE hFile,
LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
DWORD flProtect,
DWORD dwMaximumSizeHigh,
DWORD dwMaximumSizeLow,
LPCWSTR lpName
)
/*++

Routine Description:

A file mapping object can be created using CreateFileMapping

Creating a file mapping object creates the potential for mapping a
view of the file into an address space. File mapping objects may be
shared either through process creation or handle duplication.
Having a handle to a file mapping object allows for mapping of the
file. It does not mean that the file is actually mapped.

A file mapping object has a maximum size. This is used to size the
file. A file may not grow beyond the size specified in the mapping
object. While not required, it is recommended that when opening a
file that you intend to map, the file should be opened for exclusive
access. Win32 does not require that a mapped file and a file
accessed via the IO primitives (ReadFile/WriteFile) are coherent.

In addition to the STANDARD_RIGHTS_REQUIRED access flags, the
following object type specific access flags are valid for file
mapping objects:

- FILE_MAP_WRITE - Write map access to the file mapping object is
desired. This allows a writable view of the file to be
mapped. Note that if flProtect does not include
PAGE_READWRITE, this access type does not allow writing the
mapped file.

- FILE_MAP_READ - Read map access to the file mapping object is
desired. This allows a readablee view of the file to be
mapped.

- FILE_MAP_ALL_ACCESS - This set of access flags specifies all of
the possible access flags for a file mapping object.

Arguments:

hFile - Supplies an open handle to a file that a mapping object is
to be created for. The file must be opened with an access mode
that is compatible with the specified pretection flags. A value
of INVALID_HANDLE_VALUE specifies that the mapping object is
backed by the system paging file. If this is the case, a size
must be specified.

lpFileMappingAttributes - An optional parameter that may be used to
specify the attributes of the new file mapping object. If the
parameter is not specified, then the file mapping object is
created without a security descriptor, and the resulting handle
is not inherited on process creation:

flProtect - The protection desired for mapping object when the file
is mapped.

flProtect Values

PAGE_READONLY - Read access to the committed region of pages is
allowed. An attempt to write or execute the committed
region results in an access violation. The specified hFile
must have been created with GENERIC_READ access.

PAGE_READWRITE - Read and write access to the committed region
of pages is allowed. The specified hFile must have been
created with GENERIC_READ and GENERIC_WRITE access.

PAGE_WRITECOPY - Read and copy on write access to the committed
region of pages is allowed. The specified hFile must have been
created with GENERIC_READ access.

dwMaximumSizeHigh - Supplies the high order 32-bits of the maximum
size of the file mapping object.

dwMaximumSizeLow - Supplies the low order 32-bits of the maximum
size of the file mapping object. A value of zero along with a
value of zero in dwMaximumSizeHigh indicates that the size of
the file mapping object is equal to the current size of the file
specified by hFile.

lpName - Supplies the name ofthe file mapping object.

Return Value:

NON-NULL - Returns a handle to the new file mapping object. The
handle has full access to the new file mapping object and may be
used in any API that requires a handle to a file mapping object.

FALSE/NULL - The operation failed. Extended error status is available
using GetLastError.

--*/

{
HANDLE Section;
NTSTATUS Status;
LARGE_INTEGER SectionSizeData;
PLARGE_INTEGER SectionSize;
OBJECT_ATTRIBUTES Obja;
POBJECT_ATTRIBUTES pObja;
ACCESS_MASK DesiredAccess;
UNICODE_STRING ObjectName;
ULONG AllocationAttributes;
PWCHAR pstrNewObjName = NULL;

DesiredAccess = STANDARD_RIGHTS_REQUIRED | SECTION_QUERY | SECTION_MAP_READ;
AllocationAttributes = flProtect & (SEC_FILE | SEC_IMAGE | SEC_RESERVE | SEC_COMMIT | SEC_NOCACHE);
flProtect ^= AllocationAttributes;
if (AllocationAttributes == 0) {
AllocationAttributes = SEC_COMMIT;
}

if ( flProtect == PAGE_READWRITE ) {
DesiredAccess |= (SECTION_MAP_READ | SECTION_MAP_WRITE);
}
else
if ( flProtect != PAGE_READONLY && flProtect != PAGE_WRITECOPY ) {
SetLastError(ERROR_INVALID_PARAMETER);
return NULL;
}

if ( ARGUMENT_PRESENT(lpName) ) {
if (gpTermsrvFormatObjectName &&
(pstrNewObjName = gpTermsrvFormatObjectName(lpName))) {

RtlInitUnicodeString(&ObjectName,pstrNewObjName);

} else {

RtlInitUnicodeString(&ObjectName,lpName);
}

pObja = BaseFormatObjectAttributes(&Obja,lpFileMappingAttributes,&ObjectName);
}
else {
pObja = BaseFormatObjectAttributes(&Obja,lpFileMappingAttributes,NULL);
}

if ( dwMaximumSizeLow || dwMaximumSizeHigh ) {
SectionSize = §ionSizeData;
SectionSize->LowPart = dwMaximumSizeLow;
SectionSize->HighPart = dwMaximumSizeHigh;
}
else {
SectionSize = NULL;
}

if (hFile == INVALID_HANDLE_VALUE) {
hFile = NULL;
if ( !SectionSize ) {
SetLastError(ERROR_INVALID_PARAMETER);
if (pstrNewObjName) {
RtlFreeHeap(RtlProcessHeap(), 0, pstrNewObjName);
}
return NULL;
}
}

Status = NtCreateSection(
§ion,
DesiredAccess,
pObja,
SectionSize,
flProtect,
AllocationAttributes,
hFile
);

if (pstrNewObjName) {
RtlFreeHeap(RtlProcessHeap(), 0, pstrNewObjName);
}

if ( !NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return Section = NULL;
}
else {
if ( Status == STATUS_OBJECT_NAME_EXISTS ) {
SetLastError(ERROR_ALREADY_EXISTS);
}
else {
SetLastError(0);
}
}
return Section;
}
ljlln 2005-07-18
  • 打赏
  • 举报
回复
今天揭帖
zengkun100 2005-07-13
  • 打赏
  • 举报
回复
我个人认为:CreateFileMapping函数将在内存中开辟一块出来,至于大小,当然是函数中指定的。
MapViewOfFile函数将在进程的虚拟地址空间中申请一片空间,但实际上的物理内存页面并没有分配,这个时候,如果你要写这片内存的话,才会出现物理内存页面的分配,但是分配的大小我就不知道了,这里涉及到一种叫做“写拷贝”的技术。的确,你对内存的操作就象是对文件的操作一样,之后当你释放那个VIEW的时候,对内存的修改会反映到磁盘文件上去,所以减少了I/O次数。一般是4KB一次写I/O。

楼主:
我昨天下午看了几个小时MSDN上一篇讲内存映象的文章,E文的,觉得自己还是没有能够完全理解。建议你去查一下FILE MAPPING。

另外:小弟也有一篇关于内存映象的问题在版上,望不吝赐教!
ljlln 2005-07-12
  • 打赏
  • 举报
回复
请版主发表意见
sjjf 2005-07-12
  • 打赏
  • 举报
回复
mark
su5369 2005-07-12
  • 打赏
  • 举报
回复
高声问题
收了
horisly 2005-07-12
  • 打赏
  • 举报
回复
我并不是说一次Load整个文件到内存,我是说也可以模拟内存映射的做法,开一个页面大小的缓冲区。
=======
呵呵,当然不可能一次load完拉,难道说你会为一个10m的文件分配一个10m的缓冲区吗?
-------
你这样做,还是要用到磁盘IO啊,内存映射是系统调度作出的反映的,外设的速度可能比不上系统的时间片处理快拉。
sad_4978 2005-07-12
  • 打赏
  • 举报
回复
关注
亿云力科技 2005-07-12
  • 打赏
  • 举报
回复
To Horisly:

我并不是说一次Load整个文件到内存,我是说也可以模拟内存映射的做法,开一个页面大小的缓冲区。内存映射同样是读入一个页面大小的数据,比我自己读的优势在哪里呢?

谢谢
ljlln 2005-07-11
  • 打赏
  • 举报
回复
关注ing
horisly 2005-07-11
  • 打赏
  • 举报
回复
1.占用内存空间大。
2.磁盘IO一次读入速度比内存映射慢。
亿云力科技 2005-07-11
  • 打赏
  • 举报
回复
楼上说的很对,但这和我在内存中分配一个较大(1page)的一块内存,一次读入文件数据刚好装满这块内存,前者在磁盘IO方面有什么优势呢?
horisly 2005-07-11
  • 打赏
  • 举报
回复

综合一些资料得到的看法:

假设你磁盘上有一个1GB的数据文件,通过文件的映射,把文件的一部分映射到进程的虚拟地址空间(映射的区域是在0x80000000--0xBFFFFFFF),但是不提交给RAM。

windows系统会返回一个指向这块内存地址的指针。然后我们就可以通过该指针来像使用一个1GB的数组一样使用该指针。

当程序中有存取这段内存的指令的时候,由于所访问的数据尚未加载到内存的指令地址,将会产生一个页面异常。

操作系统捕捉到这个异常后,分配一页RAM,并把它映射到当前进程发生异常的地址处,然后系统把文件中的相应数据读到这个页面中,继续执行刚才产生异常的指令。这就是应用程序自己不需要调用文件IO函数的原因。
nlstone 2005-07-10
  • 打赏
  • 举报
回复
个人意见:
映射以后等价于目标文件成为虚拟内存的管理范围,解决了地址映射,页映射的一系列问题,以后在使用时将不会重新启动一系列的磁盘IO的映射转换(省的主要是这个时间),并且文件内容将会按页读入到内存,且不会马上消失(重复利用时完全没有了硬盘IO).
gohappy_1999 2005-07-10
  • 打赏
  • 举报
回复
mark
zuoluoyun 2005-07-08
  • 打赏
  • 举报
回复
内存有保留和提交两种状态,处于保留状态的在任务管理器中的进程占用空间是不会显示的.
ForTopLevel 2005-07-08
  • 打赏
  • 举报
回复
内存映射文件有两种,一种是只存在于内存,一种是存在于硬盘。对于后者,其实并没有在你创建的时候提交内存,它只是保留一段虚拟的地址空间给它,只有在对这个文件进行操作的时候,它才分配几个页(任何一个进程都不可能分配到和文件大小差不多的内存,除非你手动分配,否则系统函数不会给你这个优惠),把规定大小的数据读入内存,对于和通常IO读写的区别,我个人认为,一般文件的读写牵扯到文件路径的转化和对硬盘的寻址,而内存影射文件的读写虽然也是要通过读写硬盘来加载,但是在调用CreateFileMapping()后,系统已经有对这个文件的“快捷”调用方法,可能是直接转到底层的,通过转化后的硬盘地址调用的。回rtdb(东临碣石),系统自己保留的非分页内存是查不出来的,同意。
ljlln 2005-07-08
  • 打赏
  • 举报
回复
我映射时进程占用的内存没有增加。但是我们访问内存文件的时候内存确上来了,为什么IO的字节数为零,系统是怎么样加载到内存的?为什么不通过IO读取文件?
ljlln 2005-07-08
  • 打赏
  • 举报
回复
大侠出来了
加载更多回复(13)

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧