CreateFileMapping,MapViewOfFile,如何避免占用系统内存

时间:2009-12-10 12:36:45

标签: windows performance file-io memory-management

我正在开发一个针对桌面系统的应用程序,它可能只有256MB RAM(Windows 2000及更高版本)。在我的应用程序中,我有这个大文件(> 256MB),其中包含大约160字节/每个的固定记录。这个应用程序有一个相当漫长的过程,随着时间的推移,它将随机访问大约90%的文件(用于读写)。任何给定的记录写入远离读取该特定记录的记录访问量不会超过1,000(我可以调整此值)。

我有两个明显的选择:常规I / O(FileRead,FileWrite)和内存映射(CreateFileMapping,MapViewOfFile)。后者在具有足够内存的系统中应该更有效率,但在具有低内存的系统中,它将换掉大多数其他应用程序的内存,这在我的应用程序中是禁止的。有没有办法防止进程占用所有内存(例如,强制刷新我不再访问的内存页面)?如果这是不可能的,那么我必须回到常规I / O;我本来希望在写入部分使用重叠I / O(因为访问是如此随机),但文档说writes of less than 64K are always served synchronously

欢迎任何改进I / O的想法。

4 个答案:

答案 0 :(得分:12)

我终于找到了从线程here派生的方式。诀窍是在我需要取消的范围内使用VirtualUnlock();虽然此函数返回FALSE且错误0x9e(“段已解锁”),但实际上释放了内存,即使页面已被修改(文件已正确更新)。

这是我的示例测试程序:

#include "stdafx.h"

void getenter(void)
{
    int     ch;
    for(;;)
    {
        ch = getch();
        if( ch == '\n' || ch == '\r' ) return;
    }
}

int main(int argc, char* argv[])
{
    char*   fname = "c:\\temp\\MMFTest\\TestFile.rar";      // 54 MB
    HANDLE  hfile = CreateFile( fname, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL );
    if( hfile == INVALID_HANDLE_VALUE )
    {
        fprintf( stderr, "CreateFile() error 0x%08x\n", GetLastError() );
        getenter();
        return 1;
    }

    HANDLE map_handle = CreateFileMapping( hfile, NULL, PAGE_READWRITE | SEC_RESERVE, 0, 0, 0);
    if( map_handle == NULL )
    {
        fprintf( stderr, "CreateFileMapping() error 0x%08x\n", GetLastError() );
        getenter();
        CloseHandle(hfile);
        return 1;
    }

    char* map_ptr = (char*) MapViewOfFile( map_handle, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0, 0 );
    if( map_ptr == NULL )
    {
        fprintf( stderr, "MapViewOfFile() error 0x%08x\n", GetLastError() );
        getenter();
        CloseHandle(map_handle);
        CloseHandle(hfile);
        return 1;
    }

    // Memory usage here is 704KB
    printf("Mapped.\n"); getenter();

    for( int n = 0 ; n < 10000 ; n++ )
    {
        map_ptr[n*4096]++;
    }

    // Memory usage here is ~40MB
    printf("Used.\n"); getenter();

    if( !VirtualUnlock( map_ptr, 5000 * 4096 ) )
    {
        // Memory usage here is ~20MB
        // 20MB already freed!
        fprintf( stderr, "VirtualUnlock() error 0x%08x\n", GetLastError() );
        getenter();
        UnmapViewOfFile(map_ptr);
        CloseHandle(map_handle);
        CloseHandle(hfile);
        return 1;
    }

    // Code never reached
    printf("VirtualUnlock() executed.\n"); getenter();

    UnmapViewOfFile(map_ptr);
    CloseHandle(map_handle);
    CloseHandle(hfile);

    printf("Unmapped and closed.\n"); getenter();

    return 0;
}

正如您所看到的,在执行VirtualUnlock()后,程序的工作集会减少,就像我需要的那样。我只需要跟踪我更改的页面,以便在适当的时候解锁。

答案 1 :(得分:3)

只需将整个文件映射到内存即可。这会消耗虚拟但不是物理内存。该文件是从磁盘分段读取的,并通过管理交换文件的相同策略从内存中逐出。

答案 2 :(得分:2)

VirtualUnlock似乎不起作用。你需要做的就是打电话 紧接在UnmapViewOfFile(map_ptr)之前的FlushViewOfFile(map_ptr,0)。 Windows任务管理器不会显示物理内存使用情况。使用SysInternals的ProcessExplorer

答案 3 :(得分:1)

您是使用MapViewOfFile将整个文件映射为一个块吗?如果是,请尝试映射较小的部分。您可以使用FlushViewOfFile()

刷新视图