Архитектура памяти в Win32 API Организация «статической» виртуальной

Скачать презентацию Архитектура памяти в Win32 API Организация «статической» виртуальной Скачать презентацию Архитектура памяти в Win32 API Организация «статической» виртуальной

22482-memory_windows_ch3_2015.ppt

  • Количество слайдов: 88

>Архитектура памяти в Win32 API Организация «статической» виртуальной памяти  (Virtual Memory API) Архитектура памяти в Win32 API Организация «статической» виртуальной памяти (Virtual Memory API)

>Получение информации о ВАП  typedef struct _SYSTEM_INFO {   union { Получение информации о ВАП typedef struct _SYSTEM_INFO { union { DWORD dwOemId; struct { WORD wProcessorArchitecture; WORD wReserved; }; }; DWORD dwPageSize; LPVOID lpMinimumApplicationAddress; LPVOID lpMaximumApplicationAddress; DWORD_PTR dwActiveProcessorMask; DWORD dwNumberOfProcessors; DWORD dwProcessorType; DWORD dwAllocationGranularity; WORD wProcessorLevel; WORD wProcessorRevision; } SYSTEM_INFO; VOID GetSystemInfo ( LPSYSTEM_INFO lpSystemInfo ); размер страницы младший и старший адрес ВАП доступного процессу гранулярность блоков адресов

>Дескрипторы виртуальных адресов Для управления виртуальным адресным пространством процесса менеджер виртуальной памяти поддерживает набор Дескрипторы виртуальных адресов Для управления виртуальным адресным пространством процесса менеджер виртуальной памяти поддерживает набор структур данных, которые позволяют вести учет зарезервированных и свободных блоков (диапазонов) виртуальных адресов. Эти структуры данных называются дескрипторами виртуальных адресов (virtual address descriptors, VAD). Для каждого процесса диспетчер памяти поддерживает свой набор VAD. Для большей эффективности поиска VAD организованы в виде двоичного дерева с автоматической балансировкой.

>Пример схемы дерева VAD Пример схемы дерева VAD

>Работа приложений с виртуальной памятью  Резервирование и выделение памяти производится блоками адресов (VAD). Работа приложений с виртуальной памятью Резервирование и выделение памяти производится блоками адресов (VAD). Начальный адрес блока должен быть выровнен на значение dwAllocationGranularity (обычно равно 64K), при необходимости адрес округляется «вниз». Размер блока должен быть кратен размеру страницы dwPageSize, при необходимости округляется «вверх». Блок адресов в адресном пространстве процесса может находиться в одном из трех состояний : выделен (committed) – блоку адресов назначена физическая память либо часть файла подкачки; зарезервирован (reserved) – блок адресов помечен как занятый, но физическая память не распределена; свободен (free) – блок адресов не выделен и не зарезервирован.

>Функции API для работы виртуальной памятью Для резервирования региона памяти в адресном пространстве процесса Функции API для работы виртуальной памятью Для резервирования региона памяти в адресном пространстве процесса или выделения ее используется функция VirtualAlloc (), а для освобождения – функция VirtualFree (). Для работы в адресном пространстве произвольного процесса необходимо использовать функции VirtualAllocEx () и VirtualFreeEx (). Выделенные страницы можно заблокировать в памяти, т.е. запретить их вытеснение в файл подкачки. Для этих целей служит пара функций VirtualLock () и VirtualUnlock (). Процессу не разрешается блокировать более 30 страниц. Для изменения атрибутов защиты регионов используются функции VirtualProtect () и VirtualProtectEx ().

>Функции Win32 API для работы виртуальной памятью VirtualAlloc VirtualAllocEx VirtualFree VirtualFreeEx VirtualLock VirtualUnlock VirtualProtect Функции Win32 API для работы виртуальной памятью VirtualAlloc VirtualAllocEx VirtualFree VirtualFreeEx VirtualLock VirtualUnlock VirtualProtect VirtualProtectEx

>Состояния страниц ВП и функции Win32 API Состояния страниц ВП и функции Win32 API

>Функция VirtualAlloc LPVOID VirtualAlloc ( LPVOID lpAddress, // адрес для резервирования или выделения памяти Функция VirtualAlloc LPVOID VirtualAlloc ( LPVOID lpAddress, // адрес для резервирования или выделения памяти DWORD dwSize, // размер выделяемого региона DWORD flAllocationType, // тип распределения памяти DWORD flProtect // тип защиты доступа );

>Функция VirtualAllocEx LPVOID VirtualAllocEx ( HANDLE hProcess,  // дескриптор процесса LPVOID lpAddress, // Функция VirtualAllocEx LPVOID VirtualAllocEx ( HANDLE hProcess, // дескриптор процесса LPVOID lpAddress, // адрес для резервирования или выделения памяти DWORD dwSize, // размер выделяемого региона DWORD flAllocationType, // тип распределения памяти DWORD flProtect // тип защиты доступа );

>Параметр flAllocationType MEM_RESERVE – резервирует блок адресов без выделения памяти. MEM_COMMIT – отображает ранее Параметр flAllocationType MEM_RESERVE – резервирует блок адресов без выделения памяти. MEM_COMMIT – отображает ранее зарезервированный блок адресов на физическую память или файл подкачки, выделяя при этом память. Может комбинироваться с флагом MEM_RESERVE для одновременного резервирования и выделения. MEM_TOP_DOWN – выделяет память по наибольшему возможному адресу. Имеет смысл только при lpAddress = NULL. MEM_DECOMMIT – освободить выделенную память. MEM_RELEASE – освободить зарезервированный регион. При использовании этого флага параметр dwSize должен быть равен нулю.

>Параметр flProtect PAGE_READONLY – допускается только чтение. PAGE_READWRITE – допускается чтение и запись. PAGE_EXECUTE Параметр flProtect PAGE_READONLY – допускается только чтение. PAGE_READWRITE – допускается чтение и запись. PAGE_EXECUTE – допускается только выполнение. PAGE_EXECUTE_READ – допускается исполнение и чтение. PAGE_EXECUTE_READWRITE – допускается выполнение, чтение и запись. PAGE_GUARD – дополнительный флаг защиты, который комбинируется с другими флагами. При первом обращении к странице этот флаг сбрасывается и возникает исключение STATUS_GUARD_PAGE. Этот флаг используется для контроля размеров стека с возможностью его динамического расширения. PAGE_NOCACHE – запрещает кэширование страниц. Может быть полезен при разработке драйверов устройств (например, данные в видеобуфер должны переписываться сразу, без кэширования).

>Работа с «большими» страницами Установите для процесса уровень привилегий SeLockMemoryPrivilege с помощью функции AdjustTokenPrivileges Работа с «большими» страницами Установите для процесса уровень привилегий SeLockMemoryPrivilege с помощью функции AdjustTokenPrivileges (). Получите минимально допустимый размер для «больших» страниц с помощью функции GetLargePageMinimum (). Используйте параметр MEM_LARGE_PAGES при вызове функции VirtualAlloc (). Выравнивание начального адреса и размера блока должно быть выполнено по минимально допустимому размеру «больших» страниц.

>Пример – получение привилегий HANDLE hToken; if (!OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken))  return 0; Пример – получение привилегий HANDLE hToken; if (!OpenProcessToken (GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) return 0; LUID luid; if (!LookupPrivilegeValue (NULL, SE_LOCK_MEMORY_NAME, &luid)) return 0; TOKEN_PRIVILEGES tp; tp.PrivilegeCount = 1; tp.Privileges[0].Luid = luid; tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; if(!AdjustTokenPrivileges (hToken, FALSE, &tp, sizeof(tp), NULL, NULL) || (GetLastError() != ERROR_SUCCESS)) return 0;

>Пример – выделение «большой» страницы char *pArray = (char *) VirtualAlloc  ( Пример – выделение «большой» страницы char *pArray = (char *) VirtualAlloc ( NULL, 1 * GetLargePageMinimum(), MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);

>Функция VirtualFree BOOL VirtualFree ( LPVOID lpAddress,   // адрес освобождаемого региона DWORD Функция VirtualFree BOOL VirtualFree ( LPVOID lpAddress, // адрес освобождаемого региона DWORD dwSize, // размер освобождаемого региона DWORD dwFreeType // тип освобождения ); В случае успеха функция возвращает TRUE, FALSE – в случае неудачи.

>Параметры функции VirtualFree dwSize – размер, если мы будем использовать тип освобождения, как MEM_RELEASE, Параметры функции VirtualFree dwSize – размер, если мы будем использовать тип освобождения, как MEM_RELEASE, то размер должен быть установлен в 0. dwFreeType – будет определять какая операция произойдет с памятью: MEM_RELEASE – освобождена; MEM_DECOMMIT – зарезервирована, но не используется. При успешном выполнении функция вернет TRUE в случае успеха и FALSE – в случае неудачи.

>Функция VirtualFreeEx BOOL VirtualFreeEx ( HANDLE hProcess, // дескриптор процесса LPVOID lpAddress, // адрес Функция VirtualFreeEx BOOL VirtualFreeEx ( HANDLE hProcess, // дескриптор процесса LPVOID lpAddress, // адрес освобождаемого региона DWORD dwSize, // размер освобождаемого региона DWORD dwFreeType // тип освобождения );

>Изменение атрибутов защиты Для изменения атрибутов защиты блоков адресов используются функции VirtualProtect () и Изменение атрибутов защиты Для изменения атрибутов защиты блоков адресов используются функции VirtualProtect () и VirtualProtectEx (). VirtualProtect () позволяет изменять атрибуты защиты в адресном пространстве текущего процесса. VirtualProtectEx () позволяет изменять атрибуты защиты в адресном пространстве произвольного процесса.

>Функция VirtualProtect  BOOL VirtualProtect ( LPVOID lpAddress, // адрес региона для установки флага Функция VirtualProtect BOOL VirtualProtect ( LPVOID lpAddress, // адрес региона для установки флага DWORD dwSize, // размер региона DWORD flNewProtect, // флаги защиты PDWORD lpflOldProtect // адрес для сохранения // прежних флагов );

>Инспектирование ВАП Функции VirtualQuery () и VirtualQueryEx () позволяют определить статус указанного региона адресов. Инспектирование ВАП Функции VirtualQuery () и VirtualQueryEx () позволяют определить статус указанного региона адресов. DWORD VirtualQuery( LPCVOID IpAddress, // адрес области PMEMORY_BASICONFORMATION IpBuffer, // адрес // информационного буфера DWORD dwLength // размер буфера );

>Структура MEMORY_BASIC_INFORMATION typedef struct _MEMORY_BASIC_INFORMATION {  PVOID BaseAddress;  // базовый адрес области Структура MEMORY_BASIC_INFORMATION typedef struct _MEMORY_BASIC_INFORMATION { PVOID BaseAddress; // базовый адрес области PVOID AllocationBase; // базовый адрес выделенной области DWORD AllocationProtect; // исходная защита от доступа DWORD RegionSize; // размер области в байтах DWORD State; // состояние блока DWORD Protect; // текущая защита от доступа DWORD Type; // тип страниц // (MEM_IMAGE, MEM_MAPPED, MEM_PRIVATE) } MEMORY_BASIC_INFORMATION;

>Настройка алгоритма замещения Фиксация (блокировка) страниц в оперативной памяти – функции VirtualLock() и VirtualUnLock(). Настройка алгоритма замещения Фиксация (блокировка) страниц в оперативной памяти – функции VirtualLock() и VirtualUnLock(). Процессу разрешается блокировать не более 30 страниц. Для настройки рабочего множества процесса используется функция SetProcessWorkingSetSize (), которая может снять ограничение блокировки не более 30 страниц. Также SetProcessWorkingSetSize () позволяет задать для процесса минимальный и максимальный размер рабочего множества процесса.

>Блокировка страниц в памяти:  VirtualLock  и VirtualUnlock Функция VirtualLock () позволят зафиксировать Блокировка страниц в памяти: VirtualLock и VirtualUnlock Функция VirtualLock () позволят зафиксировать (заблокировать) страницы в ОП и предотвратить их вытеснение на диск. BOOL VirtualLock ( LPVOID lpAddress, // адрес начала памяти SIZE_T dwSize // количество байтов ); Если фиксация больше не нужна, то ее можно убрать функцией VirtualUnlock(). BOOL VirtualUnlock ( LPVOID lpAddress, // адрес начала памяти SIZE_T dwSize // количество байтов ); При успешном выполнении функции возвращают TRUE.

>Настройка рабочего множества: SetProcessWorkingSetSize BOOL SetProcessWorkingSetSize ( HANDLE hProcess, // дескриптор процесса DWORD dwMinimumWorkingSetSize, Настройка рабочего множества: SetProcessWorkingSetSize BOOL SetProcessWorkingSetSize ( HANDLE hProcess, // дескриптор процесса DWORD dwMinimumWorkingSetSize, // мин. размер рабочего мн-ва процесса, в байтах DWORD dwMaximumWorkingSetSize // макс. размер рабочего мн-ва процесса, в байтах );

>Урезание рабочего множества процесса Если и dwMinimumWorkingSetSize и dwMaximumWorkingSetSize имеют значение «–1», функция временно Урезание рабочего множества процесса Если и dwMinimumWorkingSetSize и dwMaximumWorkingSetSize имеют значение «–1», функция временно урезает рабочее множество процесса до нуля. Аналогичный результат достигается с помощью функции EmptyWorkingSet ().

>Особенности настройки рабочего множества процесса  Дескриптор процесса должен иметь права доступа PROCESS_SET_QUOTA. Если Особенности настройки рабочего множества процесса Дескриптор процесса должен иметь права доступа PROCESS_SET_QUOTA. Если значения dwMinimumWorkingSetSize или dwMaximumWorkingSetSize больше, чем текущий размер рабочего множества памяти процесса, данный процесс должен иметь привилегию SE_INC_BASE_PRIORITY_NAME.

>Получение справочной информации по ВП процесса GetProcessWorkingSetSize () – получение текущих значений минимального и Получение справочной информации по ВП процесса GetProcessWorkingSetSize () – получение текущих значений минимального и максимального размера рабочего множества процесса. GetProcessMemoryInfo () – получение расширенной статистики по использованию ВП процесса, например: количество страничных прерываний; текущий и пиковый размер рабочего множества процесса; текущее и пиковое использование файла подкачки.

>Структура MEMORYSTATUS  typedef struct _MEMORYSTATUS {   DWORD  dwLength; // размер Структура MEMORYSTATUS typedef struct _MEMORYSTATUS { DWORD dwLength; // размер структуры DWORD dwMemoryLoad; // процент используемой памяти SIZE_T dwTotalPhys; // количество байтов физической памяти SIZE_T dwAvailPhys; // кол-во свободных байтов физ. памяти SIZE_T dwTotalPageFile; // размер в байтах файла подкачки SIZE_T dwAvailPageFile; // количество свободных байтов файла подкачки SIZE_T dwTotalVirtual; // количество байтов ВАП доступных // пользователю SIZE_T dwAvailVirtual; // количество свободных байтов // ВАП, доступных пользователю } MEMORYSTATUS, *LPMEMORYSTATUS;

>Архитектура памяти в Win32 API Организация «динамической» виртуальной памяти (Heap Memory API) Архитектура памяти в Win32 API Организация «динамической» виртуальной памяти (Heap Memory API)

>«Кучи» (heaps)  Кучи (heaps) – это динамически распределяемые области данных.  При порождении «Кучи» (heaps) Кучи (heaps) – это динамически распределяемые области данных. При порождении процесса ему предоставляется куча размером 1 Мбайт по умолчанию. Ее размер может изменяться параметром /HEAP при построении исполняемого модуля. Функции библиотеки времени исполнения компилятора CRT (malloc(), free() и т. д.) используют возможности куч.

>Функции создания и использования «куч» HANDLE GetProcessHeap (VOID ) – получение дескриптора кучи по Функции создания и использования «куч» HANDLE GetProcessHeap (VOID ) – получение дескриптора кучи по умолчанию; LPVOID HeapAlloc (HANDLE hHeap, DWORD dwFlags, DWORD dwSize) – для выделения из кучи блока памяти заданного размера и возвращения указателя; LPVOID HeapReAlloc (HANDLE hHeap, DWORD dwFlags, LPVOID lpOldBlock, DWORD dwSize) – для изменения размера выделенного блока памяти с возможностью перемещения блока при необходимости (флаг запрета на перемещение HEAP_REALLOC_IN_PLACE_ONLY); BOOL HeapFree (HANDLE hHeap, DWORD dwFlags, LPVOID lpMem) – для освобождения выделенного блока памяти кучи.

>Создание дополнительных «куч» для повышения эффективности управления памятью; для уменьшения рабочего множества процесса; для Создание дополнительных «куч» для повышения эффективности управления памятью; для уменьшения рабочего множества процесса; для повышения производительности многопоточных приложений; для устранения дискриминации между потоками; для быстрого освобождение всей памяти в куче.

>Повышение эффективности управления памятью В системах со страничной организацией отсутствует проблема фрагментации физической памяти. Повышение эффективности управления памятью В системах со страничной организацией отсутствует проблема фрагментации физической памяти. Однако существует проблема фрагментации адресного пространства. В 4Gb адресном пространстве эта проблема не актуальна, но она имеет значение в 1Mb куче. Если элементы какой-либо структуры имеют один размер, а элементы другой структуры – другой размер, то полезно размещать эти структуры в разных кучах.

>Уменьшение рабочего множества процесса В соответствии с принципом локальности, работа с разными структурами, чаще Уменьшение рабочего множества процесса В соответствии с принципом локальности, работа с разными структурами, чаще всего, происходит не одновременно. Границы элементов разных структур не выровнены на границу страницы. Обращение к элементам одной структуры вызывает подкачку всей страницы, а, значит и элементов другой структуры. Это увеличивает рабочее множество процесса.

>Повышение производительности многопоточных приложений Предоставление собственной кучи для каждого потока многопоточного приложения уменьшает состязательность Повышение производительности многопоточных приложений Предоставление собственной кучи для каждого потока многопоточного приложения уменьшает состязательность между ними, в результате чего общая производительность программы может значительно повыситься.

>Устранение дискриминации между потоками Ни один из потоков не сможет получить больше памяти, чем Устранение дискриминации между потоками Ни один из потоков не сможет получить больше памяти, чем распределено для его кучи.

>Создание и уничтожение «кучи» HANDLE HeapCreate (  DWORD dwFlags, // флаги создания кучи Создание и уничтожение «кучи» HANDLE HeapCreate ( DWORD dwFlags, // флаги создания кучи DWORD dwInitialSize, // начальный размер кучи DWORD dwMaximumSize // макс. размер кучи // 0 – размер всей виртуальной памяти системы ); BOOL HeapDestroy ( HANDLE hHeap);

>Параметр dwFlags HEAP_GENERATE_EXCEPTIONS – указывает системе на то, что в случае возникновения ошибки необходимо Параметр dwFlags HEAP_GENERATE_EXCEPTIONS – указывает системе на то, что в случае возникновения ошибки необходимо генерировать исключительную ситуацию. Это будет происходить во всех случаях, когда функция должна была бы возвратить значение NULL. HEAP_NO_SERIALIZE – указывает, что пока выполняется текущий вызов HeapAlloc (), к куче не будут происходить обращения из других потоков. HEAP_ZERO_MEMORY – указывает, что выделяемая память должна инициализироваться нулями. В противном случае память не обязательно инициализируется нулями.

>Определения размера блока памяти «кучи» DWORD HeapSize(   HANDLE hHeap, // дескриптор кучи Определения размера блока памяти «кучи» DWORD HeapSize( HANDLE hHeap, // дескриптор кучи DWORD dwFlags, // управляющие флаги LPCVOID lpMem // адрес проверяемого блока памяти ); Зная адрес блока памяти, полученного из пула, вы можете определить его размер при помощи функции HeapSize (). В случае ошибки эта функция возвращает значение 0xFFFFFFFF. Если блоком памяти пользуется только один поток, то можно передать через параметр dwFlags значение HEAP_NO_SERIALIZE.

>Блокировка совместно используемой «кучи» BOOL HeapLock (HANDLE hHeap) – блокирует кучу, при использовании данной Блокировка совместно используемой «кучи» BOOL HeapLock (HANDLE hHeap) – блокирует кучу, при использовании данной функции только один поток имеет к ней доступ. Другие потоки, запрашивающие доступ, переводятся в состояние ожидания до тех пор, пока поток, владеющий кучей, не разблокирует ее. Это одна из форм синхронизации потоков, которым система реализует упорядоченность доступа к ресурсу. BOOL HeapUnlock (HANDLE hHeap) – разблокирует кучу, которая до этого была заблокирована функцией HeapLock ().

>Дополнительные возможности по управлению «кучами» UINT HeapCompact (HANDLE hHeap, DWORD fdwFlags);  BOOL HeapWalk Дополнительные возможности по управлению «кучами» UINT HeapCompact (HANDLE hHeap, DWORD fdwFlags); BOOL HeapWalk (HANDLE hHeap, PPROCESS_HEAP_ENTRY pHeapEntry); BOOL HeapValidate (HANDLE hHeap, DWORD dwFlags, LPCVOID lpMem);

>Архитектура памяти в Win32 API Файлы, проецируемые в память (memory-mapped file API) Архитектура памяти в Win32 API Файлы, проецируемые в память (memory-mapped file API)

>Проецирование файлов в память “Как и виртуальная память, проецируемые файлы позволяют резервировать регион адресного Проецирование файлов в память “Как и виртуальная память, проецируемые файлы позволяют резервировать регион адресного пространства и передавать ему физическую память. Различие между этими механизмами состоит в том, что в последнем случае физическая память не выделяется из системного страничного файла, а берется из файла, уже находящегося на диске. Как только файл спроецирован в память, к нему можно обращаться так, как будто он в нее целиком загружен.” (Джеффри Рихтер. Windows для профессионалов.)

>Проецируемые файлы Использование проецируемых файлов стирает для программиста грань между оперативной и дисковой памятью. Проецируемые файлы Использование проецируемых файлов стирает для программиста грань между оперативной и дисковой памятью. С точки зрения классической теории кэш, оперативная память и дисковое пространство – это три вида памяти, отличающиеся скоростью доступа и размером. Но если перемещением данных между кэшем и ОП занимаются процессор и ОС, то перемещение данных между ОП и диском обычно выполняет прикладной процесс с использованием функций файлового ввода-вывода. В ОС Windows менеджер виртуальной памяти занимается загрузкой и перемещением страниц адресного пространства процесса, которые могут находиться не только в файле подкачки, но и в любом спроецированном файле. Механизм проецирования файлов может быть использован процессами, работающими только на локальном компьютере; он не может быть использован для передачи данных по сети.

>Применение проецируемых файлов Для запуска исполняемых файлов (EXE) и динамически связываемых библиотек (DLL). Применение проецируемых файлов Для запуска исполняемых файлов (EXE) и динамически связываемых библиотек (DLL). Для работы с файлами. Для одновременного использования одной области данных двумя процессами.

>Использование проецируемого файла при запуске нового процесса Создание виртуального адресного пространства процесса (размером 4Gb). Использование проецируемого файла при запуске нового процесса Создание виртуального адресного пространства процесса (размером 4Gb). Резервирование в ВАП региона размером, достаточным для размещения исполняемого файла. Начальный адрес региона определяется в заголовке EXE-модуля. Обычно он равен 0x00400000. Проецирование исполняемого файла на зарезервированное адресное пространство. Аналогичным образом выполняется проецирование на ВАП процесса необходимых ему динамически связываемых библиотек. Информация о необходимых библиотеках находится в заголовке EXE-модуля. Желательное расположение региона адресов описано внутри библиотеки.

>Пример: совместное использование файла подкачки и DLL-библиотек Пример: совместное использование файла подкачки и DLL-библиотек

>Пример: одновременное использование области данных двумя процессами Пример: одновременное использование области данных двумя процессами

>Механизм проецирования файла в память  Проецирование файла данных в память: Создается объект типа Механизм проецирования файла в память Проецирование файла данных в память: Создается объект типа «файл» – функция CreateFile (). Создается объект типа «проецируемый файл» – функция CreateFileMapping (). При этом используется дескриптор файла, возвращенный функцией CreateFile (). Производится отображение объекта «проецируемый файл» или его части на ВАП процесса – функция MapViewOfFile (). Завершение проецирования файла данных: Выполняется открепление файла от адресного пространства процесса – функция UnmapViewOfFile (). Выполняется уничтожение объектов «файл» и «проецируемый файл» – функция CloseHandle ().

>Функция CreateFileMapping  HANDLE CreateFileMapping (   HANDLE hFile, // дескриптор проецируемого файла Функция CreateFileMapping HANDLE CreateFileMapping ( HANDLE hFile, // дескриптор проецируемого файла LPSECURITY_ATTRIBUTES lpAttributes, // атрибуты защиты объекта DWORD flProtect, // флаги защиты страниц DWORD dwMaximumSizeHigh, // старшее слово макс. размера DWORD dwMaximumSizeLow, // младшее слово макс. размера LPCTSTR lpName // имя объекта );

>Параметр flProtect PAGE_READONLY PAGE_READWRITE PAGE_WRITECOPY PAGE_EXECUTE_READ PAGE_EXECUTE_READWRITE SEC_COMMIT – по умолчанию SEC – проецирование Параметр flProtect PAGE_READONLY PAGE_READWRITE PAGE_WRITECOPY PAGE_EXECUTE_READ PAGE_EXECUTE_READWRITE SEC_COMMIT – по умолчанию SEC – проецирование исполняемого файла SEC_NOCACHE – все страницы раздела определяются как некэшируемые SEC_RESERVE – резервирует все страницы раздела, не выделяя физическую память

>Функция OpenFileMapping  HANDLE OpenFileMapping (   DWORD dwDesiredAccess, // режим доступа Функция OpenFileMapping HANDLE OpenFileMapping ( DWORD dwDesiredAccess, // режим доступа BOOL bInheritHandle, // флажок наследования LPCTSTR lpName // имя объекта );

>Функция проецирования области  LPVOID MapViewOfFile (   HANDLE hFileMappingObject, // дескриптор проецируемого Функция проецирования области LPVOID MapViewOfFile ( HANDLE hFileMappingObject, // дескриптор проецируемого файла DWORD dwDesiredAccess, // режим доступа DWORD dwFileOffsetHigh, // старшее DWORD смещения DWORD dwFileOffsetLow, // младшее DWORD смещения SIZE_T dwNumberOfBytesToMap // количество байт отображения //, 0 – отображать файл целиком );

>Параметр dwDesiredAccess FILE_MAP_WRITE – доступ к операциям чтения-записи, проецируемый файл должен быть создан с Параметр dwDesiredAccess FILE_MAP_WRITE – доступ к операциям чтения-записи, проецируемый файл должен быть создан с защитой PAGE_READWRITE. FILE_MAP_READ – доступ только для чтения, проецируемый файл должен быть создан с защитой PAGE_READWRITE или PAGE_READONLY. FILE_MAP_ALL_ACCESS – то же самое, что FILE_MAP_WRITE. FILE_MAP_COPY – копирование при доступе для записи, проецируемый файл должен создаваться с флажком защиты PAGE_WRITECOPY. FILE_MAP_EXECUTE – доступ к исполнению кода из отображаемой памяти, проецируемый файл должен быть создан с доступом PAGE_EXECUTE_READWRITE или PAGE_EXECUTE_READ.

>Функция проецирования области по определенному адресу LPVOID MapViewOfFileEx (   HANDLE hFileMappingObject, // Функция проецирования области по определенному адресу LPVOID MapViewOfFileEx ( HANDLE hFileMappingObject, // дескриптор отображаемого объекта DWORD dwDesiredAccess, // режим доступа DWORD dwFileOffsetHigh, // старшее DWORD смещения DWORD dwFileOffsetLow, // младшее DWORD смещения SIZE_T dwNumberOfBytesToMap, // число отображаемых байтов LPVOID lpBaseAddress // начальный адрес );

>Функция отмены проецирования области BOOL UnmapViewOfFile (   LPCVOID lpBaseAddress // начальный адрес Функция отмены проецирования области BOOL UnmapViewOfFile ( LPCVOID lpBaseAddress // начальный адрес );

>Механизм совместного использования проецируемого файла Один процесс создает объект «проецируемый файл» с помощью функции Механизм совместного использования проецируемого файла Один процесс создает объект «проецируемый файл» с помощью функции CreateFileMapping (), передавая в параметре lpName имя объекта. Другой процесс открывает уже созданный объект «проецируемый файл» по имени. Теперь два процесса могут совместно использовать объект «проецируемый файл». При этом, при помощи функции MapViewOfFile () каждый процесс проецирует этот объект на свое ВАП и используют эту часть адресного пространства как разделяемую область данных.

>Взаимодействие процессов через общую область данных  Если один процесс меняет разделяемую область данных, Взаимодействие процессов через общую область данных Если один процесс меняет разделяемую область данных, то она меняется и для другого процесса. Операционная система обеспечивает когерентность разделяемой области данных для всех процессов. Для обеспечения когерентности процессы должны работать с одним объектом “проецируемый файл”, а не с одним файлом.

>Использование файла подкачки Совместного использования несколькими процессами области файла подкачки необходимо в функцию CreateFileMapping Использование файла подкачки Совместного использования несколькими процессами области файла подкачки необходимо в функцию CreateFileMapping () передать в качестве параметра не дескриптор ранее открытого файла, а значение 0xFFFFFFFF (или -1).

>Пример проецирования файла подкачки //создание объекта «проецируемый файл» HANDLE hFileMapping =   CreateFileMapping( Пример проецирования файла подкачки //создание объекта «проецируемый файл» HANDLE hFileMapping = CreateFileMapping( (HANDLE)0xFFFFFFFF, NULL, PAGE_READWRITE, 0, 100, lpFileShareName ); CloseHandle( hFile ); //проецирование файла подкачки целиком PVOID pMassive = MapViewOfFile( hFileMapping, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0); //здесь производится работа с массивом pMassive … //завершение работы с проецированной областью UnmapViewOfFile( pMassive );

>Архитектура памяти в Win32 API Доступ к ВП другого процесса Архитектура памяти в Win32 API Доступ к ВП другого процесса

>Доступ к ВП другого процесса Ранее говорилось, что менеджер ВП изолирует ВАП процессов для Доступ к ВП другого процесса Ранее говорилось, что менеджер ВП изолирует ВАП процессов для защиты от несанкционированного доступа. Для решения задачи обмена информацией между процессами следует использовать проецируемые файлы или другие специальные технологии, которые будут рассмотрены в разделе «Межпроцессное взаимодействие». Однако есть еще один способ получить доступ к памяти другого процесса – использовать функции ReadProcessMemory () и WriteProcessMemory (). Недостаток этого метода – процесс-писатель должен установить разрешение PROCESS_VM_READ, которое предоставит ВСЕМ процессам системы право читать ВСЕ свое адресное пространство!

>Функции ReadProcessMemory и WriteProcessMemory  ReadProcessMemory () – читает данные из области памяти в Функции ReadProcessMemory и WriteProcessMemory ReadProcessMemory () – читает данные из области памяти в заданном процессе. WriteProcessMemory () – пишет данные в область памяти в заданном процессе. Пример для самостоятельной работы: http://faceh0r.narod.ru/doc/GameTrainer.html

>Функция WriteProcessMemory BOOL WriteProcessMemory (  HANDLE hProcess, // дескриптор процесса  LPVOID lpBaseAddress, Функция WriteProcessMemory BOOL WriteProcessMemory ( HANDLE hProcess, // дескриптор процесса LPVOID lpBaseAddress, // указатель на базовый адрес в // ВАП процесса, по которому должны быть записаны данные LPCVOID lpBuffer, // указатель на буфер, который содержит // данные, записываемые в ВАП заданного процесс SIZE_T nSize, // число записываемых байтов SIZE_T* lpNumberOfBytesWritten // указатель на переменную для // записи количество реально записанных байтов );

>Функции ReadProcessMemory BOOL ReadProcessMemory(     HANDLE hProcess, // дескриптор процесса Функции ReadProcessMemory BOOL ReadProcessMemory( HANDLE hProcess, // дескриптор процесса LPCVOID lpBaseAddress, // указатель на базовый адрес в // ВАП процесса, по которому выполняется чтение LPVOID lpBuffer, // указатель на буфер, в который должны // быть записаны читаемые данные из ВАП заданного процесса SIZE_T nSize, // число читаемых байтов SIZE_T* lpNumberOfBytesRead // указатель на переменную для // записи количество реально записанных байтов );

>Архитектура памяти в Win32 API Адресация расширенного адресного пространства Архитектура памяти в Win32 API Адресация расширенного адресного пространства

>Address Windowing Extensions Address Windowing Extensions (AWE) – программный интерфейс в ОС семейства Microsoft Address Windowing Extensions Address Windowing Extensions (AWE) – программный интерфейс в ОС семейства Microsoft Windows, позволяющий 32-битному приложению получить доступ к оперативной памяти, размер которой превышает размеры доступного приложению виртуального адресного пространства (2-3 Гб). Процесс отображения дополнительной памяти в адресное пространство приложения при помощи AWE называется «windowing» (оконный доступ) и сходен с концепцией «overlay» используемой, например, в DOS. AWE не зависит от расширения Physical Address Extension и не препятствует его использованию. В статье 2004 года, опубликованной в Dr. Dobb's Journal, отмечалось, что память, выделенная при помощи AWE не подлежит сохранению в swap-файле, и было высказано предположение, что в регионы AWE памяти удобно использовать для защиты данных, например, ключей шифрования.

>Функции AWE API  VirtualAlloc () – резервирует диапазон виртуального адресного пространства для использования Функции AWE API VirtualAlloc () – резервирует диапазон виртуального адресного пространства для использования под AWE (атрибут MEM_PHYSICAL). AllocateUserPhysicalPages () – выделяет физическую память для использования с AWE. MapUserPhysicalPages () – проецирует (или отключает) виртуальное пространство AWE на произвольный набор физических страниц, полученных при помощи вызова AllocateUserPhysicalPages (). MapUserPhysicalPagesScatter () – выполняет групповое проецирование (или отключение) виртуального пространства AWE на несколько блоков физических страниц. FreeUserPhysicalPages () – освобождает физическую память, которая была выделена под AWE.

>Пример использования AWE В AWE-окно в виртуальном адресном пространстве приложения проецируется блок физической памяти, Пример использования AWE В AWE-окно в виртуальном адресном пространстве приложения проецируется блок физической памяти, предварительно выделенный с помощью функции AllocateUserPhysicalPages ().

>Функция AllocateUserPhysicalPages BOOL AllocateUserPhysicalPages(   HANDLE hProcess, // дескриптор процесса  PULONG_PTR NumberOfPages, Функция AllocateUserPhysicalPages BOOL AllocateUserPhysicalPages( HANDLE hProcess, // дескриптор процесса PULONG_PTR NumberOfPages, // на входе: количество страниц на выделение, // на выходе: количество выделенных страниц RAM PULONG_PTR UserPfnArray // массив номеров фреймов, // идентифицирующий выделенные окну страницы );

>Функция MapUserPhysicalPages BOOL MapUserPhysicalPages(  PVOID lpAddress, // адрес адресного окна   ULONG_PTR Функция MapUserPhysicalPages BOOL MapUserPhysicalPages( PVOID lpAddress, // адрес адресного окна ULONG_PTR NumberOfPages, // число элементов в массиве PULONG_PTR UserPfnArray // массив фреймов страниц ); Функция отключает текущий блок оперативной памяти от адресного окна, если вместо параметра UserPfnArray передается NULL.

>Функция FreeUserPhysicalPages BOOL FreeUserPhysicalPages(   HANDLE hProcess, // дескриптор процесса   PULONG_PTR Функция FreeUserPhysicalPages BOOL FreeUserPhysicalPages( HANDLE hProcess, // дескриптор процесса PULONG_PTR NumberOfPages, // на входе: количество страниц на освобождение, // на выходе: количество освобожденных страниц RAM PULONG_PTR UserPfnArray // массив номеров фреймов, // идентифицирующий освобождаемые страницы RAM );

>Пример кода программы по иcпользованию AWE // сначала резервируем для адресного окна регион размером Пример кода программы по иcпользованию AWE // сначала резервируем для адресного окна регион размером 1 Мб ULONG_PTR ulRAMBytes = 1024 * 1024; PVOlD pvWindow = VirtualAlloc(NULL, ulRAMBytes, MEM_RESERVE | MEM_PHYSICAL, PAGE_READWRITE); // получаем размер страниц на данной процессорной платформе SYSTEM_INFO sinf; GetSystemInfo (&sinf); // вычисляем, сколько страниц памяти нужно для нашего количества байтов ULONG_PTR ulRAMPages = (ulRAMBytes + sinf.dwPageSize – 1) / sinf.dwPageSize; // создаем соответствующий массив для номеров фреймов страниц ULONG_PTR aRAMPages[ulRAMPages]; // выделяем страницы оперативной памяти (пользователь должен иметь права // на блокировка страниц в памяти) AllocateUserPhysicalPages( GetCurrentProcess(), &ulRAMPages, aRAMPages); MapUserPhysicalPages( pvWindow, ulRAMPages, aRAMPages); // обращаемся к этим страницам через виртуальный адрес pvWindow ... // освобождаем блок страниц оперативной памяти FreeUserPhysicalPages( GetCurrentProcess(), &ulRAMPages, aRAMPages); // уничтожаем адресное окно VirtualFree(pvWindow, 0, MEM_RELEASE);

>Ограничения AWE Страницы такой памяти нельзя разделять между процессами. Одну и ту же физическую Ограничения AWE Страницы такой памяти нельзя разделять между процессами. Одну и ту же физическую страницу нельзя проецировать по более чем одному виртуальному адресу в рамках одного процесса. B старых версиях Windows страницы такой памяти могут иметь единственный атрибут защиты – «для чтения и записи». B Windows Server 2003 Service Pack 1 и выше также поддерживаются атрибуты «нет доступа» и «только для чтения».

>AWE и архитектура x64 64-разрядная Windows полностью поддерживает AWE, так что перенос 32-битных приложений, AWE и архитектура x64 64-разрядная Windows полностью поддерживает AWE, так что перенос 32-битных приложений, использующих этот механизм, не вызывает никаких проблем. Однако AWE не столь полезен для 64-битных приложений, поскольку размеры их адресных пространств намного больше. Однако AWE дает возможность приложению выделять физическую память, которая никогда не сбрасывается на диск.

>Архитектура памяти в Win32 API Локальная память потока (TLS) Архитектура памяти в Win32 API Локальная память потока (TLS)

>Локальная память потока (TLS) Для решения ситуаций, когда есть данные, которые должны быть связаны Локальная память потока (TLS) Для решения ситуаций, когда есть данные, которые должны быть связаны индивидуально с каждым потоком, необходимо использовать механизм локальной памяти потока TLS (Thread Local Storage). Поток имеет доступ лишь к своим TLS-переменным, и не может обратиться к TLS-переменным любого другого потока.

>Назначение TLS Например, пусть процесс обрабатывает некоторый массив данных.  Каждый отдельных элемент массива Назначение TLS Например, пусть процесс обрабатывает некоторый массив данных. Каждый отдельных элемент массива должен быть поставлен в соответствие на обработку отдельному потоку. Встает задача передачи каждому потоку индекса обрабатываемого элемента массива: Для этого можно использовать передачу параметров через стек функции потока ThreadProc (). Тогда индекс будет храниться в локальной переменной функции ThreadProc (). Но представьте, что ThreadProc () вызывает другую функцию потом еще одну, и так поток может вызывать сотни функций с разными уровнями вложенности. Куда денется индекс элемента массива, который должен обработать поток? Да, можно передавать индекс каждой вложенной функции через стек, но это очевидно будет сказываться на эффективности программы. Решением подобной задачи является использование каждого потока своей локальной памяти – TLS.

>Виды TLS динамическая TLS: размер ячейки локальных данных – 4 байт количество локальных данных Виды TLS динамическая TLS: размер ячейки локальных данных – 4 байт количество локальных данных – ограничено требует использования функций API статическая TLS: размер ячейки локальных данных – не ограничен количество локальных данных – не ограничено не требует использования функций API

>Динамическая TLS Каждому потоку выделяется определенное количество ячеек размером 4 байта.  Количество ячеек Динамическая TLS Каждому потоку выделяется определенное количество ячеек размером 4 байта. Количество ячеек зависит от версии Windows, самое маленькое – это 64 ячейки на процесс, в ОС Windows 2000 и старше – 1088 ячеек на процесс. Количество ячеек можно определить с помощью константы TLS_MINIMUM_AVAILABLE. Для работы с динамической TLS поток может использовать четыре функции: TlsAlloc () TlsGetValue () TlsSetValue () TlsFree ()

>Функции для работы с динамической TLS: TlsAlloc  DWORD TlsAlloc (VOID);   Данная Функции для работы с динамической TLS: TlsAlloc DWORD TlsAlloc (VOID); Данная функция резервирует очередную 4-х байтную ячейку в локальной памяти потока и возвращает ее индекс. Далее этот индекс передают в функции TlsSetValue () и TlsGetValue (). Если массив ячеек TLS полностью использован, возвращаемое значение будет равно TLS_OUT_OF_INDEXES, что сообщает об ошибке выделения ячейки.

>Функции для работы с динамической TLS: TlsSetValue BOOL TlsSetValue ( DWORD dwTlsIndex, // TLS Функции для работы с динамической TLS: TlsSetValue BOOL TlsSetValue ( DWORD dwTlsIndex, // TLS индекс для сохранения значения LPVOID lpvTlsValue // адрес значения для сохранения ); Функция TlsSetValue () записывает значение в ячейку с индексом, который был возвращен функцией TlsAlloc (). В случае успеха функция возвращает TRUE, иначе – FALSE.

>Функции для работы с динамической TLS: TlsGetValue  LPVOID TlsGetValue ( DWORD dwTlsIndex // Функции для работы с динамической TLS: TlsGetValue LPVOID TlsGetValue ( DWORD dwTlsIndex // TLS индекс для получения значения ); Функция TlsGetValue () соответственно возвращает значение указанное данным индексом. В случае успеха функция возвращает TRUE, иначе – FALSE.

>Иллюстрация использования динамической TLS Иллюстрация использования динамической TLS

>Статическая TLS Статическая локальная память позволяет хранить данные любого фиксированного размера. Статическая локальная память Статическая TLS Статическая локальная память позволяет хранить данные любого фиксированного размера. Статическая локальная память потока опирается на механизмы загрузчика и свои собственные структуры. Статическая TLS не использует функции Win32 API . Компиляторы высокоуровневых языков предоставляют специальный синтаксис для работы с статической TLS. В программах на ассемблере статическую TLS придется реализовывать ее вручную.

>Синтаксис объявления переменной в статической TLS Компилятор Microsoft VC++ позволяет использовать следующий синтаксис для Синтаксис объявления переменной в статической TLS Компилятор Microsoft VC++ позволяет использовать следующий синтаксис для создания переменной специфичной для потока: Пример кода: __declspec(thread) int tls_i = 1; Этим кодом создается переменная tls_i локальная для потока, которая инициализируется значением 1. Переменная может быть любого типа. Переменная, указываемая за __declspec(thread), должна быть либо глобальной, либо статической внутри (или вне) функции. Локальную переменную с модификатором __declspec(thread) объявить нельзя.

>Ограничения на использование статической TLS Спецификатор __declspec( thread ) может быть использован только с Ограничения на использование статической TLS Спецификатор __declspec( thread ) может быть использован только с данными. TLS нельзя применять к локальным переменным. Нельзя получить адрес переменной TLS, т.к. он не является константой. Могут возникнуть проблемы с DLL, которую динамически загружают с помощью LoadLibrary (). Для DLL, которые могут быть загружены с помощью LoadLibrary () и которые используют TLS рекомендуется использовать динамическую TLS.