Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:OC Windows & OC Linux. Лабораторные работы по курсу «Операционные системы»
.pdf
Функция LockResource фиксирует данные в памяти и возвращает дальний указатель на соответствующий буфер. После фиксирования Windows не станет удалять сегмент с ресурсами из памяти, так
что приложение сможет использовать данные в любой момент времени.
После того как приложение использовало ресурс и он стал не
нужен, следует расфиксировать память ресурса, вызвав
UnlockResource. Функция определена через функцию GlobalUnlock
следующим образом:
BOOL WINAPI GlobalUnlock(HGLOBAL hGlb);
#define UnlockResource (h) GlobalUnlock (h)
Эти, а также и другие функции управления памятью мы рассмотрим позже, в отдельной главе, посвященной управлению памятью в операционной системе Windows.
Перед завершением работы приложения следует освободить полученный ресурс, вызвав функцию FreeResource:
BOOL WINAPI FreeResource(HGLOBAL hGlb);
В качестве параметра hGlb следует передать идентификатор ресурса,
полученный от функции LoadResource.
31
функцию

ЛАБОРАТОРНАЯ РАБОТА № 3
УПРАВЛЕНИЕ ПАМЯТЬЮ
Введение
Защищенный режим работы процессора накладывает на приложения свои ограничения. Если программа, составленная для MSDOS, имеет доступ к любому участку основной, расширенной или
дополнительной памяти, а также к любому оборудованию компьютера (через порты ввода/вывода), приложение Windows поставлено в
жесткие рамки.
Например, приложение может
работать только с теми блоками
памяти, которые ей принадлежат или получены от операционной
системы. Приложение не может выполнять запись в сегмент кода и
не может передавать управление в сегмент данных. Что же касается
портов ввода/вывода, то в расширенном режиме работы приложение, как правило, не имеет к ним непосредственного доступа
. Если
приложение попытается вывести данные в порт, это приведет к переключению задачи. Операционная система Windows проверит номер порта и, возможно, предоставит вам возможность что-нибудь в
него записать.
Цель работы: ознакомить студентов с механизмом управления
памятью в операционной системе Windows и функциями программного интерфейса Windows, предназначенные для работы с оперативной памятью.
О
ПИСАНИЕ РАБОТЫ
Приложение Windows может делать все что угодно, если оно
работает вместе с так называемым виртуальным драйвером или, как
его еще называют, драйвером виртуального устройства ввода/ вы-
вода. Виртуальный драйвер – это особая разновидность драйверов в
Windows. Виртуальные драйверы предназначены для создания вир-
туальных устройств ввода/вывода, предоставляемых в пользование
параллельно работающим приложениям Windows и
виртуальным
машинам MS-DOS. Так как виртуальные драйверы работают непо-
средственно с аппаратурой, для них не действует большинство ограничений, накладываемых на приложения Windows.
32

1.1. Особенности защищенного режима работы процессора
1.1.1. Адресация памяти в реальном режиме
Для адресации байта памяти в реальном режиме работы используются две 16-разрядные компоненты адреса – сегмент и смещение.
Физический адрес, который попадает на шину адреса системной
платы компьютера, складывается (в буквальном смысле этого слова)
из сдвинутой влево на четыре бита
нулевыми битами сегментной компоненты и компоненты смещения.
Перед сложением компонента смещения расширяется до 20 бит так,
что в старшие четыре бита записываются нули.
Задавая произвольные значения для сегмента и смещения, мы
можем сконструировать физический адрес для обращения к памяти
размером 1 Мбайт плюс 64 Кбайт (и минус 16 байт).
Адрес, состоящий
логическим адресом реального режима. Диапазон логических адресов от 0000h:0000h до FFFFh:OOOFh соответствует диапазону физических адресов от 00000h до FFFFFh. Этот диапазон адресов соответствует первому мегабайту оперативной памяти.
Диапазон логических адресов от FFFFh:0010h до FFFFh:FFFFh
соответствует так называемой области старшей памяти (High Memory Area). Размер области старшей памяти равен 64 Кбайт
байт, и эта память доступна в реальном режиме для процессора модели 80286 и более старших моделей.
1.1.2. Адресация памяти в защищенном режиме
В защищенном режиме, как и в реальном, логический адрес состоит из двух компонент. Однако эти компоненты называются не
сегмент и смещение, а селектор и смещение. Для
ческого адреса в процессоре 80286 используются также две таблицы
дескрипторов – глобальная таблица дескрипторов GDT (Global Descriptor Table) и локальная таблица дескрипторов LDT.
В расширенном режиме работы Windows приложения могут
пользоваться так называемой виртуальной памятью. Виртуальная
память позволяет создать иллюзию работы с оперативной памятью
огромного размера.
(Local Descriptor Table). Селектор используется для адресации
ячейки одной из таблиц дескрипторов,
информации базовый 24-разрядный адрес сегментов.
из сегмента и селектора, мы будем называть
и дополненной справа четырьмя
без 16
вычисления физи-
содержащей помимо прочей
33

Для получения физического адреса базовый адрес складывается
со смещением, расширенным до 24 разрядов. Таким образом, несмотря на то, что компоненты адреса остались, как и в реальном режиме, 16-разрядными, новая схема адресации защищенного режима
процессора 80286 позволяет адресовать до 16 Мбайт памяти, так как
в результате преобразования получается 24-разрядный физический
адрес.
Кроме индекса
ной таблицы при формировании физического адреса, селектор содержит еще два поля.
Поле TI (Table Indicator) используется для выбора таблицы дескрипторов. Как мы уже говорили, существуют таблицы дескрипторов двух типов. В любой момент времени может использоваться одна глобальная таблица дескрипторов и одна локальная таблица деск
рипторов. Если бит TI равен 0, для выборки базового адреса используется глобальная таблица дескрипторов GDT, если 1 – локальная
LDT.
Поле RPL (Requested Privilege Level) селектора содержит уровень привилегий, запрошенный программой при обращении к сегменту. Программа может обращаться только к таким сегментам, которые имеют соответствующий уровень привилегий. На этом основана защита системных данных от
или в результате программной ошибки) со стороны прикладных
программ.
Таблица дескрипторов содержит, помимо базового адреса сегмента, другую информацию, описывающую сегмент. При вычислении физического адреса процессор следит за тем, чтобы физический
адрес не выходил за пределы, указанные в дескрипторе сегмента.
Программа не может обратиться к памяти, лежащей вне
указанных в дескрипторе. Если же она попробует это сделать, ее работа будет прервана. Поэтому, создав, например, сегмент для хранения массива размером 100 байт, вы не сможете записать в него 101
байт или 10 Кбайт данных.
Поле доступа содержит уровень привилегий сегмента и информацию о типе сегмента. Существуют сегменты кода,
ных и системные сегменты. Кроме того, для сегмента кода можно
запретить операцию чтения, а для сегмента данных – операцию записи. Поэтому операционная система может создать сегменты кода,
, используемого для выбора ячейки дескриптор-
разрушения (преднамеренного
пределов,
сегменты дан-
-
34

которые можно выполнять, но нельзя читать, и сегменты данных,
защищенные от записи.
Что же касается привилегий, в процессорах 80ххх и Pentium
существуют четыре уровня привилегий – от 0 до 3, причем наибольшие привилегии соответствуют уровню 0.
В кольце 0 обычно работает ядро операционной системы. Кольцо 1 соответствует уровню привилегий драйверов, кольцо 2 – системам, таким, как системы
привилегированном кольце 3 располагаются прикладные программы, запускаемые пользователем.
1.2. Работа с памятью в приложениях Windows
1.2.1. Получение глобального блока памяти
Для получения глобального блока памяти вы должны использовать функцию GlobalAlloc :
HGLOBAL WINAPI GlobalAlloc(UINT fuAlloc, DWORD cbAlloc);
Параметр fuAlloc определяет тип выделяемой памяти. Размер
блока памяти в байтах должен передаваться через параметр cbAlloc,
причем вы можете заказать блок памяти размером больше, чем
64 Кбайт. Для стандартного режима работы Windows можно заказать блок памяти размером до 1 Мбайт без 80 байт, для расширенного – до 16 Мбайт без 64 Кбайт.
Функция возвращает идентификатор глобального блока памяти
или NULL, если Windows не может выделить память указанного
объема.
Параметр fuAlloc должен быть указан как
ция следующих значений:
управления базами данных. В наименее
логическая комбина-
Флаг Описание
GMEM_DDESHARE
Блок памяти будет использоваться совместно несколькими приложениями
при помощи механизма динамического обмена данными DDE
35

GMEM_DISCARDABLE Заказывается удаляемый блок памяти.
Этот флаг должен использоваться совместно с флагом GMEM MOVEABLE
GMEM_FIXED
GMEM_LOWER
GMEM_MOVEABLE
GMEM_NOCOMPACT
Заказывается фиксированный блок памяти. Этот флаг несовместим с флагом
GMEMMOVEABLE. При работе в среде Windows версии 3.1 в защищенном
режиме фиксированный сегмент, созданный с использованием флага GMEM
_FIXED, является перемещаемым. Для
такого сегмента в процессе перемещения логический адрес не изменяется,
но линейный (и, следовательно, физический) может изменяться
Синоним для GMEMNOTBANKED.
He используется в Windows версии 3.1
Заказывается перемещаемый блок памяти. Логический адрес перемещаемого блока памяти может изменяться.
Этот флаг несовместим с флагом
GMEM FIXED
Для удовлетворения запроса памяти не
следует – выполнять объединение всех
свободных участков памяти в один и
удалять блоки памяти, отмеченные как
удаляемые
GMEM_NODISCARD
Для удовлетворения запроса памяти не
следует выполнять объединение всех
свободных участков памяти в один
36

GMEM_NOTBANKED
Получить блок памяти вне фрейма дополнительной памяти EMS. Не используется в Windows версии 3.1
GMEM_NOTIFY
Если заказанный объект будет удален,
требуется вызов процедуры извещения. Процедура извещения назначается функцией GlobalNotify и должна
располагаться в фиксированном сегменте кода в библиотеке DLL. С ее
помощью приложение может разрешить или запретить Windows удалять
блок данных
GMEM_SHARE
GMEM_ZEROINIT
GHDN
Синоним для GMEM_DDESHARE
Во все байты блока необходимо записать нулевые значения
Синоним для комбинации флагов
GMEM_MOVEABLE и GMEM_ZEROINIT
GPTR
Синоним для комбинации флагов
GMEM_FIXED и GMEM_ZEROINIT
Идентификатор, полученный от функции GlobalAlloc, нельзя
использовать для адресации памяти непосредственно. Напомним,
что пока вы не зафиксировали блок памяти, его логический адрес
недоступен.
1.2.2. Фиксирование и расфиксирование блока памяти
Для получения доступа к полученному блоку памяти его необходимо зафиксировать, вызвав функцию GlobalLock:
void FAR* WINAPI GlobalLock(HGLOBAL hglb);
Функция GlobalLock фиксирует блок памяти, идентификатор
которого передается ей через параметр hglb и возвращает логический адрес зафиксированного блока или NULL, если указанный блок
удален или произошла ошибка.
37

В защищенном режиме работы Windows продолжает перемещать блоки памяти, зафиксированные функцией GlobalLock, изменяя базовый адрес в локальной таблице дескрипторов. Даже для
фиксированных блоков памяти вызов этой функции все же необходим, потому что нужно получить логический адрес блока памяти.
Для каждого блока памяти Windows поддерживает счетчик
фиксирований. Этот счетчик увеличивается при вызове
функции
GlobalLock и уменьшается при расфиксировании блока функцией
GlobalUnlock:
BOOL WINAPI GlobalUnlock(HGLOBAL hglb);
Если содержимое счетчика уменьшилось до нуля, функция возвращает значение FALSE. В противном случае возвращается TRUE.
Файл windowsx.h содержит макрокоманды, облегчающие работу с глобальными блоками памяти. Например, макрокоманда Glo-
balAllocPtr получает блок памяти и фиксирует его:
#define GlobalAllocPtr(flags, cb) \
(GlobalLock(GlobalAlloc((flags), (cb))))
В данном случае идентификатор полученного блока памяти не
сохраняется, так как он не нужен. Вы можете освободить
блок памя-
ти, зная только его логический адрес.
1.2.3. Определение идентификатора блока памяти по его адресу
С помощью функции GlobalHandle вы можете, зная селектор
блока памяти, определить его идентификатор:
DWORD WINAPI GlobalHandle(UINT uGlobalSel);
Параметр uGlobalSel указывает селекторную компоненту логического адреса блока памяти.
Младшее слово возвращаемого значения содержит идентификатор блока памяти, старшее – селектор блока памяти. В случае ошибки возвращается нулевое значение.
В файле windowsx.h определена макрокоманда GlobalPtrHandle,
упрощающая получение идентификатора блока памяти по его логическому адресу:
38

#define GlobalPtrHandle(lp) \
((HGLOBAL)LOWORD(GlobalHandle(SELECTOROF(lp))))
Макрокоманда SELECTOROF определена в файле windows.h и
предназначена для получения селекторной компоненты логического
адреса:
#define SELECTOROF(lp) HIWORD(lp)
В файле windows.h есть также определения для макрокоманды
OFFSETOF, возвращающей компоненту смещения, и макрокоманда
MAKELP, конструирующая указатель из компонент смещения и се-
лектора:
#define OFFSETOF(lp) LOWORD(lp)
#define MAKELP(set, off) ((void FAR*)MAKELONG((off) ,
(sel)))
#define MAKELONG (low, high) ((LONG) (((WORD)(low)) |
\
(((DWORD) ((WORD)(high))) << 16)))
1.2.4. Работа с удаляемыми блоками памяти
Для того чтобы заказать удаляемый блок памяти, вы
указать флаги GMEM_DISCARDABLE и GMEM_MOVEABLE, например: hmemGlDiscard =
GlobalAlloc(GMEM_MOVEABLE | GMEM_DISCARDABLE, 20
00001);
При необходимости Windows может удалить полученный таким
образом блок из памяти, сохранив только его идентификатор, и использовать ранее распределенную этому блоку память для других
приложений.
При попытке зафиксировать удаленный блок с помощью функции GlobalLock приложение получит от этой функции значение
NULL. В этом случае
значенную для определения состояния блока память, и проверить,
находится ли данный блок в удаленном состоянии.
следует вызвать функцию GlobalFlags, предна-
должны
39

1.2.5. Изменение блока памяти
Если вам, например, надо изменить размер заказанного ранее
блока памяти, сделав его равным 51200 байт, вы можете для этого
использовать следующий фрагмент кода:
hmemGlobal = GlobalReAlloc(hmemGlobal, 51200, GMEM_MODIFY | GMEM_DISCARDABLE | GMEM_MOVEABLE | GMEM_ZEROINIT);
После вызова функции блок памяти будет перемещаемый и
удаляемый, причем если раньше его размер был меньше 51200 байт,
во все байты дополнительной памяти будут записаны
чения.
1.2.6. Определение размера блока памяти
С помощью функции GlobalSize вы можете определить размер
блока памяти по его идентификатору:
DWORD WINAPI GlobalSize(HGLOBAL hglb);
Эта функция возвращает размер блока памяти, идентификатор
которого задан параметром hglb. Если указанный блок памяти не
существует или удален, возвращается нулевое значение.
1.2.7. Дефрагментация памяти
Если вызвать функцию GlobalCompact, операционная система
Windows выполнит
качестве параметра этой функции необходимо указать требуемый
размер непрерывного блока свободной памяти:
DWORD WINAPI GlobalCompact(DWORD dwMinFree);
Функция возвращает размер самого большого доступного непрерывного блока памяти, причем, если параметр не равен 0 или –1,
выполняется дефрагментация памяти и удаление блоков, отмеченных как удаляемые. Если параметр функции указан как 0 или
функция не выполняет дефрагментацию памяти, но возвращает правильное значение с учетом возможного выполнения дефрагментации.
1.2.8. Получение памяти в первом мегабайте адресного пространства
Если у вас возникает необходимость заказать память, доступную приложениям MS-DOS, и располагающуюся в первом мегабай-
объединение всех свободных блоков в один. В
нулевые зна-
–1,
40
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
