При разработке программ, работающих с динамической памятью,
обычно используются стандартные процедуры New, Dispose, GetMem и
FreeMem. Однако получить доступ к администратору памяти защищен-
ного режима Borland вы можете с помощью функций GlobalXXXX в мо-
дуле WinAPI.
Заметим, что функции GlobalXXXXPtr комбинируют в одной подп-
рограмме общие последовательности вызовов функций, такие как
GlobalAlloc, за которыми следуют вызовы GlobalLock, GlobalUnlock
или GlobalFree.
Подпрограммы управления памятью API
Таблица 17.2
┌─────────────────────┬─────────────────────────────────────────┐
│ Функция │ Описание │
├─────────────────────┼─────────────────────────────────────────┤
│ GetFreeSpace │ Определяет объем свободной памяти в ди-│
│ │ намически распределяемой области. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalAlloc │ Выделяет блок памяти в динамически расп-│
│ │ ределяемой области. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalAllocPtr │ Выделяет и блокирует блок памяти (с по-│
│ │ мощью вызовов GlobalAlloc и GlobalLock).│
│ │ │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalCompact │ Переупорядочивает память, распределен-│
│ │ ную в динамической области, так что ос-│
│ │ вобождается заданный объем памяти. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalDiscard │ Выгружает заданный объект памяти. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalDosAlloc │ Распределяет память, к которой можно по-│
│ │ лучить доступ в реальном режиме DOS. Эта│
│ │ память будет существовать в первом мега-│
│ │ байте линейного адресного пространства. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalDosFree │ Освобождает память, выделенную ранее с│
│ │ помощью GlobalDosAlloc. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalFlags │ Получает информацию о блоке памяти. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalFree │ Освобождает разблокированный блок памяти│
│ │ и делает его описатель недействительным.│
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalFreePtr │ Разблокирует и освобождает блок памяти│
│ │ с помощью GlobalUnlock и GlobalFree. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalHandle │ Получает описатель объекта в памяти по│
│ │ заданному адресу сегмента. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalLock │ Увеличивает счетчик ссылки блока памяти│
│ │ и возвращает указатель на него. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalLockPtr │ То же, что и GlobalLock, но вместо опи-│
│ │ сателя воспринимает указатель. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalLRUNewest │ Перемещает объект в памяти на новую не-│
│ │ давно используемую позицию, минимизируя,│
│ │ таким образом, вероятность выгрузки│
│ │ объекта. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalLRUOldest │ Перемещает объект в памяти на самую│
│ │ "старую" недавно используемую позицию,│
│ │ максимизирую вероятность выгрузки объ-│
│ │ екта. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalNorify │ Вызывает адрес экземпляра процедуры уве-│
│ │ домления, передавая описатель блока, ко-│
│ │ торый нужно выгрузить. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalPageLock │ Увеличивает значение счетчика блокиров-│
│ │ ки для памяти, связанной с данным селек-│
│ │ тором. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalPageUnlock │ Уменьшает значение счетчика блокировки│
│ │ для памяти, связанной с данным селекто-│
│ │ ром. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalPtrHandle │ По заданному указателю на блок памяти│
│ │ возвращает описатель этого блока. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalReAlloc │ Перераспределяет блок памяти. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalReAllocPtr │ Разблокирует, перераспределяет и блоки-│
│ │ рует блок памяти (используя функции│
│ │ GlobalUnlock, GlobalReAlloc и│
│ │ GlobalLock). │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalSize │ Определяет текущий размер блока памяти. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalUnfix │ Разблокирует блок памяти, блокированный│
│ │ ранее с помощью GlobalLock. │
├─────────────────────┼─────────────────────────────────────────┤
│ GlobalUnockPtr │ То же, что и GlobalUnlock, но вместо│
│ │ описателя воспринимает указатель. │
├─────────────────────┼─────────────────────────────────────────┤
│ LockSegment │ Блокирует заданный выгружаемый сегмент. │
├─────────────────────┼─────────────────────────────────────────┤
│ UnlockSegment │ Разблокирует сегмент. │
└─────────────────────┴─────────────────────────────────────────┘
Функция GlobalAlloc используется для распределения блоков
памяти. Для их освобождения применяется функция GlobalFree. Адми-
нистратор памяти поддерживает три типа блоков памяти: фиксирован-
ный, перемещаемый и выгружаемый. Фиксированный блок остается в
одних и тех же адресах физической памяти. Перемещаемый блок может
перемещаться в физической памяти и освобождать место для других
запросов на выделение памяти, а выгружаемые блоки могут выгру-
жаться из памяти, освобождая место для других блоков. С помощью
передаваемых GlobalAlloc флагов вы можете выбрать один из этих
трех типов:
* gmem_Fixed (фиксированный)
* gmem_Moveable (перемещаемый)
* gmem_Moveable + gmem_Discardable (выгружаемый)
Прикладная программа обычно выделяет только перемещаемые
блоки памяти, которые представляются типом THandle в модуле
WinAPI. Описатель памяти - это значение размером в слово, которое
идентифицирует блок памяти аналогично тому, как описатель файла -
это значение размером в слово, идентифицирующее открытый файл.
Перед тем как вы сможете получить доступ к памяти, его нужно
заблокировать с помощью функции GlobalAlloc, а когда вы закончите
к нему обращаться, его нужно разблокировать с помощью функции
GlobalUnlock. GlobalLock возвращает полный 32-разрядный указатель
на первый байт блока. Смещение указателя всегда равно 0. В защи-
щенном режиме DOS селектор указателя - это тоже самое, что описа-
тель блока, но в Windows это не всегда так.
Правильная последовательность вызовов для выделения, блоки-
ровки, разблокировки или освобождения блока показана в приведен-
ном ниже примере. В данном примере H - это переменная типа
THandle, а P - указатель:
H := GlobalAlloc(gmem_Moveable, 8192); { выделение блока }
if H <> then { если память выделена }
begin
P := GlobalLock(H); { блокировка блока }
.
. { доступ к блоку через P }
.
GlobalUnlock(H); { разблокировать блок }
GlobalFree(H); { освободить блок }
end;
Блокировка и разблокировка блока при каждом обращении к нему
достаточно утомительна и ведет к ошибкам, и реально она необходи-
ма только для выгружаемых блоков и в прикладных программах
Windows, работающих в реальном режиме. Во всех других ситуациях
лучшим решением является блокировка блока сразу после его выделе-
ния и сохранение этого состояния до освобождения блока. С этой
целью модуль WinAPI включает в себя семейство подпрограмм-"оболо-
чек" GlobalXXXXPtr. Особый интерес представляет функция
GlobalAllocPtr, которая выделяет и блокирует блок памяти, и функ-
ция GlobalFreePtr, разблокирующая и освобождающая блок памяти. С
помощью этих подпрограмм приведенный выше пример можно упростить:
H := GlobalAlloc(gmem_Moveable, 8192); { выделение блока }
if H <> then { если память выделена }
begin
.
. { доступ к блоку }
.
GlobalFreePtr(P); { освободить блок }
end;
Вызвав функцию GlobalReAlloc, вы можете изменить размер или
атрибуты блока памяти, сохранив его содержимое. Функция
GlobalReAlloc возвращает новый описатель блока, который может от-
личаться от передаваемого функции описателя, если старый размер
или новый размер блок превышает 64К. Заметим, что в тех случаях,
когда старый размер блока и новый его размер меньше 64К,
GlobalReAlloc всегда может изменить размер блока, не изменяя его
описателя.
Функция GlobalReAlloc можно также использоваться для измене-
ния атрибутов блока. Это можно сделать, задав наряду с
gmem_Moveable или gmem_Discardable флаг gmem_Modify.
Функция GlobalReAlloc выполняет те же действия, что и
GlobalReAlloc, но обе они вместо описателей использует указатели.
Имеется также ряд других, менее часто используемых
GlobalXXXX. Все они подробно описаны в Главе 1 ("Справочник по
библиотеке") "Справочного руководства программиста".