Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
R11_ДЗ_12.doc
Скачиваний:
4
Добавлен:
22.12.2018
Размер:
809.98 Кб
Скачать

Методи динамічного розподілу пам’яті

Існує три способи динамічного розподілу ОП:

  1. За допомогою процедур New і Dispose. Схеатично цей метод можна представити наступним чином:

var r : ^ real;

s : ^ string [3];

l : ^ longint; new (l); new (r); dispose (l); new (s);

...

new (l);

new (r);  r ^ r ^ r ^

...

dispose (l); l ^ l ^  s ^

new (s).

Особливості:

  • При кожному черговому створенні динамічного об'єкта пошук місця його розміщення починається з початку Heap-області (значення покажчика HeapOrg). Розміщення об'єкта здійснюється у перший вільний блок підходящого розміру. Так пам’ять під змінну s^ виділена у області, де раніше була розміщена змінна l^, оскільки розмір цієї області підходить для розміщення даної змінної.

  1. За допомогою процедур GetMem і FreeMem. Ці процедури використовуються для роботи з нетипізованими покажчиками. На відміну від процедур New-Dispose вони виділяють і звільняють блок Heap-області відповідно до зазначеного розміру. Їх формат:

GetMem (<покажчик>, <розмір>);

FreeMem (<покажчик>, <розмір>);

де <покажчик> - змінна типу pointer,

<розмір> - задається константою типу word або визначається функцією SizeОf, яка повертає як результат розмір ОП, необхідний для збереження зазначеної як параметр змінної.

Наприклад,

var

m : ^ real;

p : pointer;

begin

...

GetMem (p, 4*1024); { р вказує на блок пам'яті 4Кб }

GetMem (m, n* SizeOf (m)); { m вказує на блок пам'яті n* SizeOf (m) }

...

FreeMem (p, 4*1024); { звільнити пам'ять для p }

FreeMem (m, n* SizeOf (m)); { звільнити пам'ять для m }

...

end.

Виклики GetMem і FreeMem повинні відповідати один одному: звільняти треба стільки пам'яті, скільки було виділено, і по тому ж самому покажчику.

  1. За допомогою процедур Mark і Relеase. Цей спосіб дає можливість звільняти відразу блок динамічної пам'яті. Для цього спочатку за допомогою процедури

Mark (<покажчик>)

фіксується поточний стан Heap-області (запам'ятовується значення покажчика HeapPtr, який містить адресу початку вільної динамічної пам’яті), а потім за допомогою процедури

Release (<покажчик>)

Heap-область повертається до того стану, який було збережено відповідним викликом Mark (знищуються всі динамічні змінні, створені за допомогою процедури New або GetMem після виклику процедури Mark).

Схеатично динамічний розподіл ОП за допомогою процедур Mark-Relеase можна представити наступним чином:

var p : pointer;

q, r1, r2 : ^ real;

s : ^string [11];

begin

new (q);

mark (p);

new (s);

new (r1);

release (p);

new (r2);

end.

Особливості:

  • Специфіка розміщення динамічних об'єктів полягає у тому, що пам'ять у Heap-області виділяється не побайтно, а 8-байтовими порціями. Тому, незалежно від істиного розміру динамічного об'єкту, пам'ять під нього виділяється 8-байтовыми частинами (так для s виділиться 16 байт замість 11).

Стандартні засоби аналізу стану Heap-області

При роботі з Heap-областю, зокрема, для аналізу ресурсів пам'яті перед розміщенням динамічних змінних, можуть використовуватися ряд спеціальних функцій. У мові Pascal це функції:

SizeOf

-

повертає як результат розмір пам'яті, необхідний для зберігання зазначеної як параметр змінної (як параметр цієї функції може використовуватися не тільки змінна, але і ідентифікатор типу)

MaxAvail

-

повертає довжину в байтах найбільшої вільної ділянки в Heap-області

MemAvail

-

повертає сумарне значення всіх вільних областей пам'яті в Heap-області

Наприклад,

1) var pl : ^longint ;

begin

...

if MaxAvail >= 4 then New (pl)

else writeln (‘ Динамічну пам'ять вичерпано ‘);

...

2) if MaxAvail >= SizeOf (mas) then p:= New (mas) ;

3) writeln (‘ Розмір пам'яті в Неар-області = ‘, MemAvail) ;

New (р);

writeln (‘ Heap після розміщення р ‘, MemAvail);

Таким чином, загальний алгоритм роботи з динамічними об'єктами в програмі передбачає:

  • оголошення статичного покажчика, в термінах якого будуть задаватися дії над динамічним об’єктом;

  • виділення пам'яті під відповідну динамічну змінну;

  • ініціалізацію покажчика на динамічну змінну (присвоєння йому адреси виділеної під відповідну змінну області динамічної пам'яті);

  • виконання дій з динамічною змінною;

  • звільнення динамічної пам'яті після використання динамічної змінної.

При цьому програміст сам повинен резервувати місце під динамічну змінну, визначати значення покажчиків, звільняти пам'ять (видаляти динамічні змінні).

Звичайно, замість будь-якої статичної змінної можна використовувати динамічну, але без реальної необхідності цього робити не варто. По-перше, змінні простих типів немає сенсу розміщувати в динамічній пам'яті, оскільки вони займають менше місця, ніж покажчик на них. Наприклад, покажчик на ціле займає 4 байти, саме ціле - 2 байти. По-друге, робота з динамічними даними уповільнює виконання програми, оскільки доступ до об'єкта відбувається у два кроки: спочатку шукається покажчик, потім по ньому – сам об'єкт. Тобто, виграш в пам'яті компенсується програшем у часі.

Робота з вказівниками передбачена в багатьох мовах програмування. Наприклад, у мові С покажчики використовуються практично в будь-якій програмі. У Pascal роль покажчиків дещо скромніша.

Приклад. Знаходження суми парних чисел масиву sз 100 цілих чисел.

program Sum_Ch1; program Sum_Ch2;

var i, s : integer; type mas = array [0..100] of integer;

m : array [0..100] of integer; var i, s : integer;

begin m : ^mas;

s:=0; begin

for i:=0 to 100 do s:=0;

if (m[i] mod 2)=0 then s:=s+m[i]; New (m);

writeln (‘s=‘, s); for i:=0 to 100 do

end. if (m^[i] mod 2)=0 then s:=s+m^[i];

Dispose (m);

writeln (‘s=‘, s);

end.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]