Подтвердить что ты не робот

CreateFileMapping, MapViewOfFile, как избежать поддержки системной памяти

Я разрабатываю приложение, предназначенное для настольных систем, которые могут иметь всего 256 МБ ОЗУ (Windows 2000 и выше). В моем приложении у меня есть этот большой файл ( > 256 МБ), который содержит фиксированные записи около 160 байт/каждый. Это приложение имеет довольно длительный процесс, в котором со временем он будет случайно получать около 90% файла (для чтения и записи). Любая записанная запись не будет содержать более 1000 записей доступа от чтения этой конкретной записи (я могу настроить это значение).

У меня есть два очевидных варианта для этого процесса: регулярный ввод-вывод (FileRead, FileWrite) и сопоставление памяти (CreateFileMapping, MapViewOfFile). Последнее должно быть намного более эффективным в системах с достаточной памятью, но в системах с низкой памятью он заменит большую часть памяти других приложений, что в моем приложении не имеет значения. Есть ли способ удержать процесс от съедания всей памяти (например, как принудительное удаление страниц памяти, к которым я больше не обращаюсь)? Если это невозможно, то я должен вернуться к регулярному вводу/выводу; Мне хотелось бы использовать перекрывающиеся ввода-вывода для записывающей части (поскольку доступ настолько случайный), но в документации говорится: записи менее 64K всегда обслуживаются синхронно.

Приветствуются любые идеи по улучшению ввода-вывода.

4b9b3361

Ответ 1

Наконец я нашел способ, полученный из потока здесь. Хитрость заключается в использовании 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(), как мне было нужно. Мне нужно только следить за страницами, которые я меняю, чтобы разблокировать по мере необходимости.

Ответ 2

Просто скопируйте весь файл в память. Это потребляет виртуальную, но не физическую память. Файл читается с диска кусочно и вытесняется из памяти теми же политиками, которые управляют файлом подкачки.

Ответ 3

VirtualUnlock не работает. Что вам нужно сделать, так это позвонить FlushViewOfFile (map_ptr, 0) непосредственно перед UnmapViewOfFile (map_ptr). Диспетчер задач Windows не отображает использование физической памяти. Использовать ProcessExplorer из SysInternals

Ответ 4

Вы сопоставляете весь файл как один блок с MapViewOfFile? Если да, попробуйте сопоставить меньшие части. Вы можете очистить представление с помощью FlushViewOfFile()