
ОС / 6. ОС - Управление памятью
.pdf
21
Виды памяти процесса
Память, выделяемая системой для программы и данных процесса при его создании (при запуске EXE-файла).
Регионы виртуальной памяти, выделяемые по запросам нитей процесса. Используется для получения больших массивов памяти.
Память, получаемая нитями из «кучи» процесса (heap). Используется для получения большого числа небольших областей памяти.
Стек, выделяемый системой каждой нити процесса. Используется для хранения адресов возврата, параметров и локальных переменных при вызове функций.
Операционные системы. Управление памятью

22
Выделение регионов памяти
Функция VirtualAlloc позволяет получить регион виртуальной памяти.
Параметры:
виртуальный адрес начала региона. Если NULL – система сама выбирает место в виртуальной памяти;
размер региона (система округляет его до целого числа страниц по 4 КБ);
тип выделения:
MEM_RESERVE – память отмечается как занятая. При попытке обратиться к резервированной памяти (как и к нерезервированной) произойдет фатальная ошибка;
MEM_COMMIT – для региона или его части выделяется место в страничном файле. Физическая память будет выделяться только при обращении к адресам, как было описано выше;
можно комбинировать оба флага: MEM_RESERVE + MEM_COMMIT;
MEM_RESET – регион или его часть не должны сохраняться в страничном файле, даже если есть изменения.
Операционные системы. Управление памятью

23
Выделение регионов памяти
Функция VirtualAlloc – еще параметры:
тип доступа:
PAGE_READONLY – только чтение, запись и исполнение запрещены;
PAGE_READWRITE – чтение и запись, исполнение запрещено;
PAGE_EXECUTE – только исполнение;
PAGE_EXECUTE_READWRITE – всё дозволено;
PAGE_EXECUTE_WRITECOPY – особая обработка для EXE- и DLL-файлов (см. ниже);
PAGE_GUARD – особая обработка для стека (см. ниже). Этот флаг комбинируется с одним из предыдущих;
PAGE_NOACCESS – всё запрещено. Зачем – не знаю. ;-)
Функция возвращает виртуальный адрес региона (или NULL).
Операционные системы. Управление памятью

24
Изменение и освобождение регионов
Функция VirtualProtect – позволяет изменить тип доступа к региону или его части. Например, с PAGE_READONLY на PAGE_READWRITE и т.п.
Функция VirtualFree – освобождает ранее выделенный регион или его часть.
Параметры:
адрес региона или его части;
размер освобождаемой области;
тип освобождения:
MEM_DECOMMIT – отменяет только MEM_COMMIT;
MEM_RELEASE – полностью освобождает память.
Операционные системы. Управление памятью

25
Отображение исполняемых файлов
При запуске EXE или при загрузке DLL система использует тот же механизм выделения регионов.
Основное отличие: за виртуальными страницами закрепляются физические страницы не в страничном файле, а прямо в файле EXE или DLL.
При этом используется флаг PAGE_EXECUTE_WRITECOPY. Это значит:
одна физическая страница может использоваться несколькими процессами, пока они только читают данные и команды;
если один из процессов пытается записать на такую страницу, то возникает исключение и система копирует для него данную страницу в страничный файл, где процесс может с ней делать, что хочет, не мешая другим процессам.
Таким образом, загрузки в память всего файла при запуске не происходит, используется стандартный механизм загрузки по требованию.
Исключение: если EXEили DLL-файл запускается с дискеты или с CD/DVD, то он сразу целиком копируется в память или в страничный файл.
Операционные системы. Управление памятью

26
Файлы, отображаемые в память
Еще одно применение механизма регионов – объекты типа File Mapping.
Основная идея: отображать виртуальные страницы не на страничный файл и не на запускаемый EXE, а на произвольно заданный открытый файл. Это дает сразу две красивые возможности:
к содержимому файла можно обращаться, не используя функций чтения/записи, просто указывая виртуальный адрес, как к ячейкам массива. При таком обращении система обязана будет прочитать требуемую страницу в память (demand paging);
если виртуальные страницы двух разных процессов отображены на один и тот же файл, то фактически получается общая область памяти, доступная обоим процессам. То, что один процесс туда запишет, другой сможет прочитать.
Операционные системы. Управление памятью

27
Работа с отображаемыми файлами
Функция CreateFileMapping – создание объекта типа File Mapping.
Параметры:
хэндл предварительно открытого файла, который будет отображаться на память;
тип доступа к объекту (только для чтения или и для записи);
размер объекта;
имя объекта (используется, чтобы разные процессы могли работать с одним и тем же объектом).
Функция возвращает хэндл созданного объекта.
Особый случай: если вместо хэндла открытого файла указано значение -1, то объект будет связан со страничным файлом. Такой объект можно использовать только для создания области памяти, общей для двух или более процессов.
Операционные системы. Управление памятью

28
Работа с отображаемыми файлами
Функция MapViewOfFile – отображает участок файла на виртуальные адреса процесса.
Параметры:
хэндл объекта File Mapping;
размер отображаемого участка файла (окна);
смещение этого участка от начала файла.
Функция возвращает виртуальный адрес участка файла.
После этого можно обращаться к данным участка файла как к адресам памяти .
Если два процесса отображают свои страницы памяти на один и тот же участок файла – получается общая память процессов.
Операционные системы. Управление памятью

29
Отображение файла в память двух процессов
Адресное пространство процесса A
Окно A
Объект |
Общий участок памяти |
|
процессов A и B |
||
FileMapping |
||
|
Окно B
Адресное пространство процесса B
Операционные системы. Управление памятью

30
Работа со стеком
При создании новой нити процесса система по умолчанию резервирует ей регион стека размером 1 МБ.
Напомним, что стек заполняется «сверху вниз» (по уменьшению адресов).
Верхняя страница стека передается с флагом MEM_Commit.
Следующая (вниз) страница – с флагом MEM_COMMIT и атрибутом PAGE_GUARD. Это означает, что при первом обращении к этой странице возникает исключение, система снимает PAGE_GUARD с этой страницы и устанавливает MEM_COMMIT и PAGE_GUARD для следующей страницы.
Самая нижняя страница стека никогда не получает MEM_COMMIT и служит таким образом барьером от переполнения стека.
Если всё же происходит обращение к барьерной странице, то генерируется другое исключение – переполнение стека. Программа пользователя может его перехватить и обработать, запросив увеличение стека. В противном случае процесс завершается по ошибке.
Операционные системы. Управление памятью