精华内容
下载资源
问答
  • 内存映射文件

    2018-04-14 20:19:26
    内存映射文件允许我们创建和修改那些因为太大而不能放入内存的文件。有了内存映射文件,我们就可以假定整个文件都放到内存中,而且可以完全把他当作非常大的数组来访问。这种方法极大的简化了用于修改文件的代码 ...

    内存映射文件允许我们创建和修改那些因为太大而不能放入内存的文件。有了内存映射文件,我们就可以假定整个文件都放到内存中,而且可以完全把他当作非常大的数组来访问。这种方法极大的简化了用于修改文件的代码

    1.类 MappedByteBuffer

    1.1描述

    public abstract class MappedByteBuffer
    extends ByteBuffer

    直接字节缓冲区,其内容是文件的内存映射区域。
    映射的字节缓冲区是通过 FileChannel.map 方法创建的。此类用特定于内存映射文件区域的操作扩展 ByteBuffer 类。
    映射的字节缓冲区和它所表示的文件映射关系在该缓冲区本身成为垃圾回收缓冲区之前一直保持有效。
    映射的字节缓冲区的内容可以随时更改,例如,在此程序或另一个程序更改了对应的映射文件区域的内容的情况下。这些更改是否发生(以及何时发生)与操作系统无关,因此是未指定的。

    1.2与普通缓存区的区别:

    全部或部分映射的字节缓冲区可能随时成为不可访问的,例如,如果我们截取映射的文件。试图访问映射的字节缓冲区的不可访问区域将不会更改缓冲区的内容,并导致在访问时或访问后的某个时刻抛出未指定的异常。因此强烈推荐采取适当的预防措施,以避免此程序或另一个同时运行的程序对映射的文件执行操作(读写文件内容除外)。

    除此之外,映射的字节缓冲区的功能与普通的直接字节缓冲区完全相同。

    展开全文
  • 内存映射文件能让你创建和修改那些因为太大而无法放入内存的文件。有了内存映射文件,你就可以认为文件已经全部读进了内存,然后把它当成一个非常大的数组来访问。这种解决办法能大大简化修改文件的代码。  ...

    内存映射文件:MappedByteBuffer 

    内存映射文件能让你创建和修改那些因为太大而无法放入内存的文件。有了内存映射文件,你就可以认为文件已经全部读进了内存,然后把它当成一个非常大的数组来访问。这种解决办法能大大简化修改文件的代码。

     FileChannel提供了map方法来把文件影射为内存映像文件:

    fileChannel.map(FileChannel.MapMode mode, longposition, long size)将此通道的文件区域直接映射到内存中。注意,你必须指明,它是从文件的哪个位置开始映射的,映射的范围又有多大;也就是说,它还可以映射一个大文件的某个小片断。

    更突出的优势是共享内存,内存映射文件可以被多个进程同时访问,起到一种低时延共享内存的作用。

    内存映射文件是一种允许Java程序直接从内存访问的特殊文件。通过将整个文件或者文件的一部分映射到内存中、操作系统负责获取页面请求和写入文件,应用程序就只需要处理内存数据,这样可以实现非常快速的IO操作。用于内存映射文件的内存在Java的堆空间以外。Java中的java.nio包支持内存映射文件,可以使用MappedByteBuffer来读写内存。MappedByteBuffer是ByteBuffer的子类,因此它具备了ByteBuffer的所有方法。

    展开全文
  • windows 内存映射文件

    千次阅读 2012-09-20 08:21:21
    4.内存管理机制--内存映射文件 (Map)  和虚拟内存一样,内存映射文件可以用来保留一个进程地址区域;但是,与虚拟内存不同,它提交的不是物理内存或是虚拟页文件...访问大数据文件,如果文件太大,比如超过了进程用户

    4.内存管理机制--内存映射文件 (Map)
       和虚拟内存一样,内存映射文件可以用来保留一个进程地址区域;但是,与虚拟内存不同,它提交的不是物理内存或是虚拟页文件,而是硬盘上的文件。

    ·使用场合
    它有三个主要用途:
    系统加载EXE和DLL文件,操作系统就是用它来加载exe和dll文件建立进程,运行exe。这样可以节省页文件和启动时间。
    访问大数据文件,如果文件太大,比如超过了进程用户区2G,用fopen是不能对文件进行操作的。这时,可用内存映射文件。对于大数据文件可以不必对文件执行I/O操作,不必对所有文件内容进行缓存。
    进程共享机制,内存映射文件是多个进程共享数据的一种较高性能的有效方式,它也是操作系统进程通信机制的底层实现方法。RPC、COM、OLE、DDE、窗口消息、剪贴板、管道、Socket等都是使用内存映射文件实现的。

    ·系统加载EXE和DLL文件

    EXE文件格式
    每个EXE和DLL文件由许多节(Section)组成,每个节都有保护属性:READ,WRITE,EXECUTE和SHARED(可以被多个进程共享,关闭页面的COPY-ON-WRITE属性)。
    以下是常见的节和作用:
    节名      作用
    .text   .exe和.dll文件的代码
    .data   已经初始化的数据
    .bss    未初始化的数据
    .reloc 重定位表(装载进程的进程地址空间)
    .rdata 运行期只读数据
    .CRT    C运行期只读数据
    .debug 调试信息
    .xdata 异常处理表
    .tls    线程的本地化存储
    .idata 输入文件名表
    .edata 输出文件名表
    .rsrc   资源表
    .didata 延迟输入文件名表

    加载过程
    1.系统根据exe文件名建立进程内核对象、页目和页表,也就是建立了进程的虚拟空间。
    2.读取exe文件的大小,在默认基地址0x0040 0000上保留适当大小的区域。可以在链接程序时用/BASE 选项更改基地址(在VC工程属性\链接器\高级上设置)。提交时,操作系统会管理页目和页表,将硬盘上的文件映射到进程空间中,页表中保存的地址是exe文件的页偏移。
    3.读取exe文件的.idata节,此节列出exe所用到的所有dll文件。然后和exe文件一样,将dll文件映射到进程空间中。如果无法映射到基地址,系统会重新定位。
    4.映射成功后,系统会把第一页代码加载到内存,然后更新页目和页表。将第一条指令的地址交给线程指令指针。当系统执行时,发现代码没有在内存中,会将exe文件中的代码加载到内存中。              

    第二次加载时(运行多个进程实例)

    1.建立进程、映射进程空间都跟前面一样,只是当系统发现这个exe已经建立了内存映射文件对象时,它就直接映射到进程空间了;只是当系统分配物理页面时,根据节的保护属性赋予页面保护属性,对于代码节赋予READ属性,全局变量节赋予COPY-ON-WRITE属性。

    2.不同的实例共享代码节和其他的节,当实例需要改变页面内容时,会拷贝页面内容到新页面,更新页目和页表。

    3.对于不同进程实例需要共享的变量,exe文件有一个默认的节, 给这个节赋予SHARED属性。

    4.你也可以创建自己的SHARED节
    #pragma data_seg(“节名”)
    Long instCount;
    #pragma data_seg()
    然后,你需要在链接程序时告诉编译器节的默认属性。
    /SECTION: 节名,RWS
    或者,在程序里用以下表达式:
    #pragma comment(linker,“/SECTION:节名,RWS”)
    这样的话编译器会创建.drective节来保存上述命令,然后链接时会用它改变节属性。
    注意,共享变量有可能有安全隐患,因为它可以读到其他进程的数据。
    C++程序:多个进程共享变量举例
    *.cpp开始处:
    #pragma data_seg(".share")
    long shareCount=0;
    #pragma data_seg()
    #pragma comment(linker,"/SECTION:.share,RWS")
    ShareCount++;
    注意,同一个exe文件产生的进程会共享shareCount,必须是处于同一个位置上的exe。

    ·访问大数据文件

    创建文件内核对象
    使用CreateFile(文件名,访问属性,共享模式,…) API可以创建。
    其中,访问属性有:
    0 不能读写 (用它可以访问文件属性)
    GENERIC_READ
    GENERIC_WRITE
    GENERIC_READ|GENERIC_WRITE;

    共享模式:
    0 独享文件,其他应用程序无法打开
    FILE_SHARE_WRITE
    FILE_SHARE_READ|FILE_SHARE_WRITE
    这个属性依赖于访问属性,必须和访问属性不冲突。
    当创建失败时,返回INVALID_HANDLE_VALUE。

    C++程序如下:
    试图打开一个1G的文件:
       MEMORYSTATUS memStatus;
       GlobalMemoryStatus(&memStatus);
       HANDLE hn=CreateFile(L"D:\\1G.rmvb",GENERIC_READ|GENERIC_WRITE,
       FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
       if(hn==INVALID_HANDLE_VALUE)
          cout<<"打开文件失败!"<<endl;
       FILE *p=fopen("D:\\1G.rmvb","rb");
       if(p==NULL)
          cout<<"用fopen不能打开大文件!"<<endl;
       MEMORYSTATUS memStatus2;
       GlobalMemoryStatus(&memStatus2);
       cout<<"打开文件后的空间:"<<endl;
       cout<<"减少物理内存="<<memStatus.dwAvailPhys-memStatus2.dwAvailPhys<<endl;
       cout<<"减少可用页文件="<<memStatus.dwAvailPageFile-memStatus2.dwAvailPageFile<<endl;
       cout<<"减少可用进程空间="<<memStatus.dwAvailVirtual-memStatus2.dwAvailVirtual<<endl<<endl;
    结果如下:

    可见,系统需要一些内存来管理内核对象,每一次运行的结果都不一样,但差别不会太大。
    用c语言的fopen不能打开这么大的文件。理论上,32位系统能支持232字节,但是,进程空间只有2G,它只能表示那么大的空间。

    创建文件映射内核对象
    API如下:
    HANDLE CreateFileMapping(Handle 文件,PSECURITY_ATTRIBUTES 安全属性,DWORD 保护属性,DWORD 文件大小高32位,DWORD 文件大小低32位,PCTSTR 映射名称)
    “文件”是上面创建的句柄;
    “安全属性”是内核对象需要的,NULL表示使用系统默认的安全属性;“保护属性”是当将存储器提交给进程空间时,需要的页面属性:PAGE_READONLY, PAGE_READWRITE和PAGE_WRITECOPY。这个属性不能和文件对象的访问属性冲突。除了这三个外,还有两个属性可以和它们连接使用(|)。当更新文件内容时,不提供缓存,直接写入文件,可用SEC_NOCACHE;当文件是可执行文件时,系统会根据节赋予不同的页面属性,可用SEC_IMAGE。另外,SEC_RESERVE和SEC_COMMIT用于稀疏提交的文件映射,详细介绍请参考下文。
    “文件大小高32位”和“文件大小低32位”联合起来告诉系统,这个映射所能支持的文件大小(操作系统支持264B文件大小);当这个值大于实际的文件大小时,系统会扩大文件到这个值,因为系统需要保证进程空间能完全被映射。值为0默认为文件的大小,这时候如果文件大小为0,创建失败。
    “映射名称”是给用户标识此内核对象,供各进程共享,如果为NULL,则不能共享。
    对象创建失败时返回NULL。
    创建成功后,系统仍未为文件保留进程空间。
    C++程序:
       MEMORYSTATUS memStatus2;
       GlobalMemoryStatus(&memStatus2);
       HANDLE hmap=CreateFileMapping(hn,NULL,PAGE_READWRITE,0,0,L"Yeming-Map");
       if(hmap==NULL)
         cout<<"建立内存映射对象失败!"<<endl;
       MEMORYSTATUS memStatus3;
       GlobalMemoryStatus(&memStatus3);
       cout<<"建立内存映射文件后的空间:"<<endl;
       cout<<"减少物理内存="<<memStatus2.dwAvailPhys-memStatus3.dwAvailPhys<<endl;
       cout<<"减少可用页文件="<<memStatus2.dwAvailPageFile-memStatus3.dwAvailPageFile<<endl;
       cout<<"减少可用进程空间="<<memStatus2.dwAvailVirtual-memStatus3.dwAvailVirtual<<endl<<endl;
    结果如下:

    默认内存映射的大小是1G文件。没有损失内存和进程空间。它所做的是建立内核对象,收集一些属性。

    文件映射内核对象映射到进程空间
    API如下:
    PVOID MAPViewOfFile(HANDLE 映射对象,DWORD访问属性,DWORD 偏移量高32位,DWORD 偏移量低32位,SIZE_T 字节数)
    “映射对象”是前面建立的对象;
    “访问属性”可以是下面的值:FILE_MAP_WRITE(读和写)、FILE_MAP_READ、FILE_MAP_ALL_ACCESS(读和写)、FILE_MAP_COPY。当使用FILE_MAP_COPY时,系统分配虚拟页文件,当有写操作时,系统会拷贝数据到这些页面,并赋予PAGE_READWRITE属性。
    可以看到,每一步都需要设置这类属性,是为了可以多点控制,试想,如果在这一步想有多种不同的属性操作文件的不同部分,就比较有用。
    “偏移高32位”和“偏移低32位”联合起来标识映射的开始字节(地址是分配粒度的倍数);
    “字节数”指映射的字节数,默认0为到文件尾。
    当你需要指定映射到哪里时,你可以使用:
    PVOID MAPViewOfFile(HANDLE 映射对象,DWORD访问属性,DWORD 偏移量高32位,DWORD 偏移量低32位,SIZE_T 字节数,PVOID 基地址)
    “基地址”是映射到进程空间的首地址,必须是分配粒度的倍数。
    C++程序:
       MEMORYSTATUS memStatus3;
       GlobalMemoryStatus(&memStatus3);
       LPVOID pMAP=MapViewOfFile(hmap,FILE_MAP_WRITE,0,0,0);
       cout<<"映射内存映射文件后的空间:"<<endl;
       if(pMAP==NULL)
         cout<<"映射进程空间失败!"<<endl;
       else
         printf("首地址=%x\n",pMAP);
       MEMORYSTATUS memStatus4;
       GlobalMemoryStatus(&memStatus4);
       cout<<"减少物理内存="<<memStatus3.dwAvailPhys-memStatus4.dwAvailPhys<<endl;
       cout<<"减少可用页文件="<<memStatus3.dwAvailPageFile-memStatus4.dwAvailPageFile<<endl;
       cout<<"减少可用进程空间="<<memStatus3.dwAvailVirtual-memStatus4.dwAvailVirtual<<endl<<endl;
    结果如下:

    进程空间减少了1G,系统同时会开辟一些内存来做文件缓存。

    使用文件
    1.对于大文件,可以用多次映射的方法达到访问的目的。有点像AWE技术。
    2.Windows只保证同一文件映射内核对象的多次映射的数据一致性,比如,当有两次映射同一对象到二个进程空间时,一个进程空间的数据改变后,另一个进程空间的数据也会跟着改变;不保证不同映射内核对象的多次映射的一致性。所以,使用文件映射时,最好在CreateFile时将共享模型设置为0独享,当然,对于只读文件没这个必要。
    C++程序:使用1G的文件
       MEMORYSTATUS memStatus4;
       GlobalMemoryStatus(&memStatus4);
       cout<<"读取1G文件前:"<<endl;
       cout<<"可用物理内存="<<memStatus4.dwAvailPhys<<endl;
       cout<<"可用页文件="<<memStatus4.dwAvailPageFile<<endl;
       cout<<"可用进程空间="<<memStatus4.dwAvailVirtual<<endl<<endl;
       int* pInt=(int*)pMAP;
       cout<<"更改前="<<pInt[1000001536/4-1]<<endl;//文件的最后一个整数
       for(int i=0;i<1000001536/4-1;i++)
         pInt[i]++;
       pInt[1000001536/4-1]=10;
       pInt[100]=90;
       pInt[101]=100;
       cout<<"读取1G文件后:"<<endl;
       MEMORYSTATUS memStatus5;
       GlobalMemoryStatus(&memStatus5);
       cout<<"可用物理内存="<<memStatus5.dwAvailPhys<<endl;
       cout<<"可用页文件="<<memStatus5.dwAvailPageFile<<endl;
       cout<<"可用进程空间="<<memStatus5.dwAvailVirtual<<endl<<endl;
    结果如下:

    程序将1G文件的各个整型数据加1,从上图看出内存损失了600多兆,但有时候损失不过十几兆,可能跟系统当时的状态有关。
    不管怎样,这样你完全看不到I/O操作,就像访问普通数据结构一样方便。

    保存文件修改
    为了提高速度,更改文件时可能只更改到了系统缓存,这时,需要强制保存更改到硬盘,特别是撤销映射前。
    BOOL FlushViewOfFile(PVOID 进程空间地址,SIZE_T 字节数)
    “进程空间地址”指的是需要更改的第一个字节地址,系统会变成页面的地址;
    “字节数”,系统会变成页面大小的倍数。
    写入磁盘后,函数返回,对于网络硬盘,如果希望写入网络硬盘后才返回的话,需要将FILE_FLAG_WRITE_THROUGH参数传给CreateFile。
    当使用FILE_MAP_COPY建立映射时,由于对数据的更改只是对虚拟页文件的修改而不是硬盘文件的修改,当撤销映射时,会丢失所做的修改。如果要保存,怎么办?
    你可以用FILE_MAP_WRITE建立另外一个映射,它映射到进程的另外一段空间;扫描第一个映射的PAGE_READWRITE页面(因为属性被更改),如果页面改变,用MoveMemory或其他拷贝函数将页面内容拷贝到第二次映射的空间里,然后再调用FlushViewOfFile。当然,你要记录哪个页面被更改。

    撤销映射
    用以下API可以撤销映射:
    BOOL UnmapViewOfFile(PVOID pvBaseAddress)
    这个地址必须与MapViewOfFile返回值相同。

    关闭内核对象

    在不需要内核对象时,尽早将其释放,防止内存泄露。由于它们是内核对象,调用CloseHandle(HANDLE)就可以了。
    在CreateFileMapping后马上关闭文件句柄;
    在MapViewOfFile后马上关闭内存映射句柄;
    最后再撤销映射。

    ·进程共享机制

    基于硬盘文件的内存映射
    如果进程需要共享文件,只要按照前面的方式建立内存映射对象,然后按照名字来共享,那么进程就可以映射这个对象到自己的进程空间中。
    C++程序如下:
       HANDLE mapYeming=OpenFileMapping(FILE_MAP_WRITE,true,L"Yeming-Map");
       if(mapYeming==NULL)
         cout<<"找不到内存映射对象:Yeming-Map!"<<endl;
       MEMORYSTATUS memStatus3;
       GlobalMemoryStatus(&memStatus3);
       LPVOID pMAP=MapViewOfFile(mapYeming,FILE_MAP_WRITE,0,0,100000000);
       cout<<"建立内存映射文件后的空间:"<<endl;
       if(pMAP==NULL)
         cout<<"映射进程空间失败!"<<endl;
       else
         printf("首地址=%x\n",pMAP);
       MEMORYSTATUS memStatus4;
       GlobalMemoryStatus(&memStatus4);
       cout<<"减少物理内存="<<memStatus3.dwAvailPhys-memStatus4.dwAvailPhys<<endl;
       cout<<"减少可用页文件="<<memStatus3.dwAvailPageFile-memStatus4.dwAvailPageFile<<endl;
       cout<<"减少可用进程空间="<<memStatus3.dwAvailVirtual-memStatus4.dwAvailVirtual<<endl<<endl;
       int* pInt=(int*)pMAP;
       cout<<pInt[100]<<endl;
    结果如下:

    在2.exe中打开之前1.exe创建的内存映射对象(当然,1.exe得处于运行状态),然后映射进自己的进程空间,当1.exe改变文件的值时,2.exe的文件对应值也跟着改变,Windows保证同一个内存映射对象映射出来的数据是一致的。可以看见,1.exe将值从90改为91,2.exe也跟着改变,因为它们有共同的缓冲页。

    基于页文件的内存映射
    如果只想共享内存数据时,没有必要创建硬盘文件,再建立映射。可以直接建立映射对象:
    只要传给CreateFileMapping一个文件句柄INVALID_HANDLE_VALUE就行了。所以,CreateFile时,一定要检查返回值,否则会建立一个基于页文件的内存映射对象。接下来就是映射到进程空间了,这时,系统会分配页文件给它。
    C++程序如下:
       HANDLE hPageMap=CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE,0,100000000,L"Yeming-Map-Page");
       if(hPageMap==NULL)
         cout<<"建立基于页文件的内存映射对象失败!"<<endl;
       MEMORYSTATUS memStatus6;
       GlobalMemoryStatus(&memStatus6);
       cout<<"建立基于页文件的内存映射文件后的空间:"<<endl;
       cout<<"减少物理内存="<<memStatus5.dwAvailPhys-memStatus6.dwAvailPhys<<endl;
       cout<<"减少可用页文件="<<memStatus5.dwAvailPageFile-memStatus6.dwAvailPageFile<<endl;
       cout<<"减少可用进程空间="<<memStatus5.dwAvailVirtual-memStatus6.dwAvailVirtual<<endl<<endl;           
       LPVOID pPageMAP=MapViewOfFile(hPageMap,FILE_MAP_WRITE,0,0,0);        
    结果如下:

    可见,和基于数据文件的内存映射不同,现在刚建立内核对象时就分配了所要的100M内存。好处是,别的进程可以通过这个内核对象共享这段内存,只要它也做了映射。

    稀疏内存映射文件
    在虚拟内存一节中,提到了电子表格程序。虚拟内存解决了表示很少单元格有数据但必须分配所有内存的内存浪费问题;但是,如果想在多个进程之间共享这个电子表格结构呢?
    如果用基于页文件的内存映射,需要先分配页文件,还是浪费了空间,没有了虚拟内存的优点。
    Windows提供了稀疏提交的内存映射机制。
    当使用CreateFileMapping时,保护属性用SEC_RESERVE时,其不提交物理存储器,使用SEC_COMMIT时,其马上提交物理存储器。注意,只有文件句柄为INVALID_HANDLE_VALUE时,才能使用这两个参数。
    按照通常的方法映射时,系统只保留进程地址空间,不会提交物理存储器。
    当需要提交物理内存时才提交,利用通常的VirtualAlloc函数就可以提交。
    当释放内存时,不能调用VirtualFree函数,只能调用UnmapViewOfFile来撤销映射,从而释放内存。
    C++程序如下:
       HANDLE hVirtualMap=CreateFileMapping(INVALID_HANDLE_VALUE,NULL,PAGE_READWRITE|SEC_RESERVE,0,100000000,L"Yeming-Map-Virtual");
       if(hPageMap==NULL)
          cout<<"建立基于页文件的稀疏内存映射对象失败!"<<endl;
       MEMORYSTATUS memStatus8;
       GlobalMemoryStatus(&memStatus8);
       cout<<"建立基于页文件的稀疏内存映射文件后的空间:"<<endl;
       cout<<"减少物理内存="<<memStatus7.dwAvailPhys-memStatus8.dwAvailPhys<<endl;
       cout<<"减少可用页文件="<<memStatus7.dwAvailPageFile-memStatus8.dwAvailPageFile<<endl;
       cout<<"减少可用进程空间="<<memStatus7.dwAvailVirtual-memStatus8.dwAvailVirtual<<endl<<endl;
       LPVOID pVirtualMAP=MapViewOfFile(hVirtualMap,FILE_MAP_WRITE,0,0,0);
       cout<<"内存映射进程后的空间:"<<endl;
       if(pVirtualMAP==NULL)
          cout<<"映射进程空间失败!"<<endl;
       else
          printf("首地址=%x\n",pVirtualMAP);
       MEMORYSTATUS memStatus9;
       GlobalMemoryStatus(&memStatus9);
       cout<<"减少物理内存="<<memStatus8.dwAvailPhys-memStatus9.dwAvailPhys<<endl;
       cout<<"减少可用页文件="<<memStatus8.dwAvailPageFile-memStatus9.dwAvailPageFile<<endl;
       cout<<"减少可用进程空间="<<memStatus8.dwAvailVirtual-memStatus9.dwAvailVirtual<<endl<<endl;
    结果如下:

    用了SEC_RESERVE后,只是建立了一个内存映射对象,和普通的一样;不同的是,它映射完后,得到了一个虚拟进程空间。现在,这个空间没有分配任何的物理存储器给它,你可以用VirtualAlloc 提交存储器给它,详细请参考上一篇<虚拟内存(VM)>。
    注意,你不可以用VirtualFree来释放了,只能用UnmapViewOfFile来。
    C++程序如下:
       LPVOID pP=VirtualAlloc(pVirtualMAP,100*1000*1000,MEM_COMMIT,PAGE_READWRITE);
       MEMORYSTATUS memStatus10;
       GlobalMemoryStatus(&memStatus10);
       cout<<"减少物理内存="<<memStatus9.dwAvailPhys-memStatus10.dwAvailPhys<<endl;
       cout<<"减少可用页文件="<<memStatus9.dwAvailPageFile-memStatus10.dwAvailPageFile<<endl;
       cout<<"减少可用进程空间="<<memStatus9.dwAvailVirtual-memStatus10.dwAvailVirtual<<endl<<endl;
       bool result=VirtualFree(pP,100000000,MEM_DECOMMIT);
       if(!result)
         cout<<"释放失败!"<<endl;
       result=VirtualFree(pP,100000000,MEM_RELEASE);
       if(!result)
         cout<<"释放失败!"<<endl;
       CloseHandle(hVirtualMap);
       MEMORYSTATUS memStatus11;
       GlobalMemoryStatus(&memStatus11);
       cout<<"增加物理内存="<<memStatus11.dwAvailPhys-memStatus10.dwAvailPhys<<endl;
       cout<<"增加可用页文件="<<memStatus11.dwAvailPageFile-memStatus10.dwAvailPageFile<<endl;
       cout<<"增加可用进程空间="<<memStatus11.dwAvailVirtual-memStatus10.dwAvailVirtual<<endl<<endl;
       result=UnmapViewOfFile(pVirtualMAP);
       if(!result)
          cout<<"撤销映射失败!"<<endl;
       MEMORYSTATUS memStatus12;
       GlobalMemoryStatus(&memStatus12);
       cout<<"增加物理内存="<<memStatus12.dwAvailPhys-memStatus11.dwAvailPhys<<endl;
       cout<<"增加可用页文件="<<memStatus12.dwAvailPageFile-memStatus11.dwAvailPageFile<<endl;
       cout<<"增加可用进程空间="<<memStatus12.dwAvailVirtual-memStatus11.dwAvailVirtual<<endl<<endl;
    结果如下:

    可以看见,用VirtualFree是不能够释放这个稀疏映射的;最后用UnmapViewOfFile得以释放进程空间和物理内存。

    展开全文
  • java 内存映射文件

    2016-05-10 14:22:40
    package io; //Creating a very large file using mapping. //{RunByHand} import java.nio.*; import java.nio.channels.*; import java.io.*;.../*内存映射文件允许修改那些因为太大而不能放入内
    package io;
    //Creating a very large file using mapping.
    //{RunByHand}
    import java.nio.*;
    import java.nio.channels.*;
    import java.io.*;
    import static net.mindview.util.Print.*;
    /*内存映射文件允许修改那些因为太大而不能放入内存的文件。*/
    public class LargeMappedFiles {
    static int length = 0x8FFFFFF; // 128 MB
    public static void main(String[] args) throws Exception {
     MappedByteBuffer out =new RandomAccessFile("test.dat", "rw").getChannel().map(FileChannel.MapMode.READ_WRITE, 0, length);
     //为了既能读又能写,先由RandomAccessFile开始,获得文件的通道,然后调用map()产生MappedByteBuffer,
     //这是一种特殊类型的直接缓冲器,需指定映射文件的初始位置和映射区域的长度,即意味着可以映射大文件的较小部分。
     for(int i = 0; i < length; i++)
       out.put((byte)'x');
     print("Finished writing");
     for(int i = length/2; i < length/2 + 6; i++)
       printnb((char)out.get(i));
    }
    } ///:~
    

    展开全文
  • 内存映射文件允许我们创建和修改哪些因为太大而不能放入内存的文件。有了内存映射文件,我们就可以假定整个文件都放在内存中,而且完全可以把它当做非常大的数组来访问。这种方法极大地简化了用于修改文件的代码。 ...
  • 内存映射文件能让你创建和修改那些因为太大而无法放入内存的文件。有了内存映射文件,你就可以认为文件已经全部读进了内存,然后把它当成一个非常大的数组来访问。这种解决办法能大大简化修改文件的代码。...
  • 有一个一维int数组,大概11G,如何用内存映射文件存储?之前用内存映射文件存储过4G以内的数据,效率挺高的,但是数据量太大以后不知道如何存储。向各位大神请教。
  • 内存映射文件允许创建和修改因为太大而不能放入内存的文件。 1. 内存映射文件简单实例 import java.io.IOException; import java.io.RandomAccessFile; import java.nio.MappedByteBuffer; import java.nio....
  • 作为访问文件的一种方式,内存映射文件的确使用相当方便.只需在正常的CreateFile完成后通过CreateFileMapping映射到内存,之后就可以像访问内存那样的使用文件了.而且此时文件的缓存是由系统自动调节的,性能和安全性都...
  • Windows的内存映射大文件读写

    千次阅读 2011-09-29 10:28:33
    Windows上,内存映射文件,使得文件的读写不会消耗多的内存,也减少了频繁的cpu指令。另外,windows上的进程间共享数据,也是通过内存映射文件的方式来实现。 刚好又遇到这个需求,需要在服务器上一次载入几十...
  • 今天对比了一下内存映射文件的性能和普通文件的测试,不比不知道,一比吓一跳啊。差距太大了。     public class FileTest { static int length = 0x8000000; // 128 Mb public void doMemTest() { ...
  • 4.内存管理机制--内存映射文件 (Map) 和虚拟内存一样,内存映射文件可以用来保留一个进程地址区域;但是,与虚拟内存不同,它提交的不是物理内存或是虚拟页文件,而是硬盘上的文件。·使用场合它有三个主要用途:...
  • PE文件内存映射

    2019-01-02 14:42:55
    在执行一个PE文件的时候,windows 并不在一开始就将整个文件读入内存的,二十采用与内存映射文件类似的机制。也就是说,windows 装载器在装载的时候仅仅建立好虚拟地址和PE文件之间的映射关系。 当且仅当真正执行到...
  • python小点心--内存文件映射

    千次阅读 2016-03-07 19:18:27
    内存文件映射,这东西听起来很高大上,其实呢,很简单,就是把一个文件映射内存中,你可以认为,映射后,文件内存中,访问速度是极快的。windows 64位环境下,最大可以映射4G的文件。说是映射,并不是真的把文件...
  • Windows核心编程——内存映射

    千次阅读 2018-11-21 13:55:44
    Windows上,内存映射文件,使得文件的读写不会消耗多的内存,也减少了频繁的cpu指令。另外,windows上的进程间共享数据,也是通过内存映射文件的方式来实现。 刚好又遇到这个需求,需要在服务器上一次载入几十兆...
  • 1.什么是通道: 有java.nio.channels包定义的。Channel表示IO源与目标打开...在最开始的时候程序等IO操作就是通过系统的IO接口与CPU进行交互,从而进行读写的操作,但是这样对于CPU来说负担太大,大大降低了CPU的利...
  • 共享内存的原理:文件映射

    千次阅读 2018-08-26 18:53:23
    mmap()是将指定的文件利用虚拟内存技术映射内存中去,在内存中建立页表项,但mmap()调用建立的页表项后面地址为空,只有使用到某个地址空间时才给此页面分配空间,要涉及到页面置换,因而需要有一定的物理内存做...
  •  内存映射实在大文件处理的时候使用的,其原理是将大文件直接拷贝到内存里面,然后直接访问,这样会比较快,如果文件太大,内存里面装不下,就一部分一部分地加载,读取,操作等等。 直接文件操作: 1:Win32API...
  • 系统:centos 语言:c++ 背景:搜索引擎的索引数据...这样虽然会使单个搜索节点更加稳定,但是磁盘比内存的缺点就更加显露无疑了,那就是存取数据慢,所以我们就想使用mmap的预读策略和文件的磁盘缓存来解决缺页...
  • 文件太大,没法一次读取到内存进行操作?Windows提供了内存映射API来读取大文件,与普通文件读取相比,内存映射效率比较高。 从代码层面上看,从硬盘上将文件读入内存,都要经过文件系统进行数据拷贝,并且数据拷贝...
  • 存储器映射文件

    2013-08-26 11:39:59
    存储器映射文件允许我们创建和修改那些因为太大而不能放入内存的文件。有了存储器映射 文件,我们就可以假定整个文件都在内存中,而且可以完全把它当作非常大的数组来访问。 这种方法极大地简化了用于修改文件的...

空空如也

空空如也

1 2 3 4 5 ... 11
收藏数 216
精华内容 86
关键字:

内存映射文件太大