Использование кучи в Delphi. 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Использование кучи в Delphi.



Программируя в Delphi мы постоянно явно или неявно взаимодействуем с менеджером кучи. Неявно его используют все функции или конструкции языка, требующие выделения памяти: создания объекта класса, создание динамического массива или длинной строки. Явное взаимодействие с этим механизмом происходит при использовании следующих функций Delphi: New, Dispose, GetMem, AllocMem, ReallocMem, FreeMem.

procedure New(var P: Pointer);

Функция выделяет динамическую память в куче. Параметром принимает типизированный указатель, затем инициирует его адресом выделенного участка. Не имеет смысла использовать функцию с нетипизированным указателем, он просто останется со значением NIL.

procedure Dispose(var P: Pointer);

Функция освобождает память в куче. Параметром принимает типизированный указатель возвращенный функцией New(). Используется только в паре с функцией выделения памяти New().

function summ(var1, var2: integer): integer;var f_int: ^integer; s_int: ^integer; begin // выделим память new(f_int); new(s_int); f_int^:= var1; s_int^:= var2; Result:= f_int^ + s_int^; // освободим память dispose(f_int); dispose(s_int); end;

Вышеприведенные функции используются для динамического выделения памяти с использованием типизированных указателей малого размера. Для работы с двоичными буферами и иными структурами данных большого размера используется следующий набор функций.

procedure GetMem(var P: Pointer; Size: Integer);

Выделяет блок памяти указанного размера. Можно использовать нетипизированный указатель. Если свободной памяти не окажется, то будет сгенирированно исключение EOutOfMemory. После выделения в памяти содержится всякий мусор.

function AllocMem(Size: Cardinal): Pointer;

Соответствует функции GetMem(), но после выделения память будет инициирована нулями. Возвращает указатель, как результат, а не как параметр, в отличие от той же GetMem().

procedure ReallocMem(var P: Pointer; Size: Integer);

Деиствие зависит от значений P и Size. P может быть пустым указателем или содержать адрес участка памяти, возвращенный функциями GetMem, AllocMem и ReallocMem.
Варианты:
((P = NIL) and (Size = 0)): ReallocMem ничего ни делает;

((P = NIL) and (Size <> 0)): выделяет новый блок памяти и устанавливает P на его адрес. Можно использовать вместо GetMem();

((P <> NIL) and (Size = 0)): освобождает память, адресуемую P. P будет установлен в NIL. Похоже на FreeMem(), но в отличае от него чистит указатель.

((P <> 0) and (Size <> 0)): перевыделяет указанный блок памяти (изменяет его размер). Существующие данные затронуты не будут, но если память увеличиться, то новое пространство будет содержать всякий мусор. Если для изменения размера не будет хватать памяти, то блок может быть перенесен на другое место в пределах кучи, P будет указывать на новое место.

procedure FreeMem(var P: Pointer[; Size: Integer]);

Функция освобождает память, выделенную в GetMem и AllocMem. Может принимать размер памяти, которую нужно освободить. Надо быть крайне осторожным с этим параметром, так как тут может появиться утечка. После освобождения памяти указатель P будет содержать мусор. Если в качестве параметра передана структура, содержащая длинные строки, варианты, динамические массивы или интерфейсы, тогда перед выполнением FreeMem будет вызвана Finalize.

Небольшой пример:

procedure useMemoryManager;type // шаблончик для доступа к памяти побайтово memcells = array[0..$7FFFFFFE] of byte; var p: pointer; i: integer; begin // выделим память GetMem(p, 100); // и инициируем ее какими-нибудь числами for i:=0 to 99 do memcells(p^)[i]:= byte(i); // добавим памяти ReallocMem(p, 200); // и допишим числа for i:=0 to 99 do memcells(p^)[i+100]:= byte(i+100); // … посмотрим, что получилось for i:=0 to 199 do writeln(inttostr(memcells(p^)[i])); // уберем после себя FreeMem(p);end;

Работа с менеджером памяти

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

Во-первых есть несколько глобальных переменных, управляемых менеджером.

var AllocMemCount: integer;

Эта переменная содержит количество выделенных блоков памяти. Используется для определения оставшихся блоков.
Использовать эту переменную стоит с осторожностью. Например, в статически слинкованных программах, модули будут иметь свои собственные экземпляры AllocMemCount.

var AllocMemSize: integer;

Содержит размер в байтах всех выделенных блоков. Сколько всего памяти из кучи выделенно программе. Эта переменная тоже глобальна, поэтому так же как и AllocMemCount следует использовать с осторожностью.

var HeapAllocFlags: word;

Набор флагов, устанавливающих опции для менеджера памяти. (по умолчанию – GMEM_MOVEABLE)

GMEM_FIXED Выделяет фиксированную память. Т.к. ОС не может перемещать блоки памяти в юзермод, то и нет нужды блокировать память (не может комбинироваться с GMEM_MOVEABLE)
GMEM_MOVEABLE Выделяет перемещаемую память. В юзермод блоки не могут быть перемещены, если они расположены в физической памяти, но могут перемещаться в пределах кучи.
GMEM_ZEROINIT При выделении памяти (например, функцией GetMem) все байты этой памяти будут выставлены в 0
GMEM_MODIFY Используется для изменения атрибутов выделенного блока памяти
GMEM_DDESHARE Введёны для совместимости с 16-разрядными версиями, но может использоваться для оптимизации DDE операций.
GMEM_SHARE - // -
GPTR GMEM_FIXED + GMEM_ZEROINIT
GHND GMEM_MOVEABLE + GMEM_ZEROINIT

Во-вторых, существует ряд полезных функций для управления менеджером.

function GetHeapStatus(): TheapStatus;

Узнать текущее состояние диспетчера памяти.
Структура TheapStatus:

THeapStatus = record // Размер памяти в байтах которая доступна программе TotalAddrSpace: Cardinal; // Сколько памяти из TotalAddrSpace не находятся в SWAPе TotalUncommitted: Cardinal; // Сколько памяти из TotalAddrSpace находятся в SWAPе TotalCommitted: Cardinal; // Сколько всего динамической памяти выделено программе TotalAllocated: Cardinal; // Сколько памяти еще доступно для выделения (увеличивается) TotalFree: Cardinal; // Сколько памяти доступно в маленьких блоках FreeSmall: Cardinal; // Сколько памяти доступно в больших блоках // непрерывно идущие маленькие блоки могут складываться FreeBig: Cardinal; // Доступная, но еще не выделявшаяся память Unused: Cardinal; // Размер памяти используемой для нужд менеджера Overhead: Cardinal; // Внутренний статус кучи HeapErrorCode: Cardinal; end;

Если используется SharedMem, то статус относится к куче разделяемой несколькими процессами.



Поделиться:


Последнее изменение этой страницы: 2017-02-21; просмотров: 501; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.129.70.157 (0.005 с.)