Разделы адресного пространства
Функции API для работы с памятью (virtualAlloc и virtualFree) позволяют процессу получить страницы памяти или возвратить их системе. Процесс отведения памяти имеет несколько ступеней, когда блоки памяти постепенно проходят через определенные состояния. Страницы памяти в виртуальном адресном пространстве процесса могут пребывать в одном из трех возможных состояний.
Таблица 12.2. Состояния страниц памяти в виртуальном адресном пространстве процесса.
Состояние | Описание |
---|---|
Free | Страница недоступна, но ее можно либо зарезервировать (reserve) для процесса, либо отдать процессу (committed) |
Reserved | Зарезервированный блок памяти недоступен процессу и не связан с какой-либо физической памятью, но он подготовлен для того, чтобы в любое время быть отданным (committed) процессу. Зарезервированный диапазон адресов не может быть отдан другому потоку этого же процесса. Такой способ работы снижает фрагментарность физической памяти, так как обычно память резервируется для какой-либо динамической структуры с учетом ее будущего роста. |
Committed | Отданная страница представляет интересы уже реальной физической памяти как в RAM, так и на диске. Она может иметь различную степень доступа для процесса. (Readonly, ReadWrite и т. д.) |
Память, которую процесс отводит, вызывая функцию virtualAlloc, доступна только этому процессу. Если какая-то DLL в пространстве процесса отводит себе новую память, то она размещается в пространстве процесса, вызвавшего DLL, и недоступна для других процессов, одновременно пользующихся услугами той же DLL. Иногда необходимо создать блок памяти, который был бы общим для нескольких процессов или DLL, используемых несколькими процессами. Для этой цели существует такой объект ядра системы, как файлы, проецируемые в память (file mapping).
Два процесса создают два упомянутых объекта с одним и тем же именем, получают описатель (handle) объекта и работают с ним так, как будто этот объект находится в памяти. На самом деле они работают с одними и теми же страницами физической памяти. Заметьте, что эта память не является глобальной, так как она остается недоступной для других процессов. Кроме того, ей могут соответствовать различные виртуальные адреса в пространствах разных процессов, ее разделяющих. Если процессы намерены записывать в общую память, то во избежание накладок вы должны использовать синхронизирующие объекты ядра Windows (семафоры, мьютексы, события).
Алгоритм работы с динамической памятью процесса довольно сильно отличается от привычного алгоритма работы с динамической памятью области heap в программах на языке C++. Там вы с помощью операции new отводите память определенного размера, работаете с ней и затем освобождаете ее операцией delete. Здесь необходимы более сложные манипуляции:
- резервирование диапазона адресов в виртуальном пространстве процесса. Физическая память при этом не выделяется;
- отдача (commiting) процессу какого-то количества страниц из предварительно зарезервированного диапазона адресов. При этом процессу становится доступной физическая память, соответствующая виртуальной. Здесь одновременно указывается тип доступа к выделенным страницам (read-write, read-only, или no access). Сравните с обычным способом, который всегда выделяет страницы с доступом read-write;
- освобождение диапазона зарезервированных страниц;
- освобождение диапазона отданных страниц. Здесь освобождается физическая память.
Кроме того, возможна операция блокирования страниц памяти в RAM, которая запрещает системе перемещать их в страничный файл подкачки (paging file). Есть функция, позволяющая определить текущее состояние диапазона страниц и изменить тип доступа к ним.