Процедури GetMem та FreeMem - Програмування від
І нігда небажано виділяти пам'ять тим способом, як це робить New. Вам може знадобитися виділити більше або менше пам'яті, ніж це робить за замовчуванням New, або до початку виконання ви можете просто не знати, скільки пам'яті вам потрібно використовувати. Borland Pascal виконує такий розподіл за допомогою процедури GetMem.
П роцедура GetMem сприймає два параметри: змінну-покажчик, для якої ви хочете розподілити пам'ять, і число байт, що розподіляються.
Динамічне виділення пам'яті для рядка
Нехай, наприклад, у вас є прикладна програма, яка зчитує 1000 рядків з файлу і записує їх в динамічну пам'ять. Ви не знаєте, наскільки довгим буде кожен з цих рядків, тому вам потрібно буде описати рядковий тип такого розміру, який буде відповідати максимальному можливому рядку. Якщо припустити, що не всі рядки мають максимальну довжину, у вас буде марно використовувати пам'ять.
Щоб вирішити цю проблему, ви можете рахувати кожен рядок у буфер, потім виділити стільки пам'яті, скільки потрібно для фактичних даних у рядку. Приклад цього показано нижче:
У місце виділення для рядків 256К (256 символів на рядок 1000 разів) ви виділили 4К (4 байти на покажчик 1000 разів) плюс обсяг, фактично займаний текстом.
Звільнення виділеної пам'яті
А так само, як потрібно звільняти пам'ять, виділену за допомогою New, вам потрібно звільняти пам'ять, розподілену за допомогою процедури GetMem. Це можна зробити за допомогою процедури FreeMem. Аналогічно тому, як кожному виклику New повинен відповідати парний виклик Dispose, кожному виклику процедури GetMem має відповідати виклик FreeMem.
Як і GetMem, процедура FreeMemсприймає два параметри: змінну, що звільняється, і обсяг пам'яті, що звільняється. Важливо, щоб обсяг пам'яті, що звільняється, точно збігався з об'ємом виділеної пам'яті. New і Dispose, виходячи з типі покажчика, завжди знають, скільки байт потрібно виділяти чи звільняти. Але у випадку GetMem і FreeMem обсяг пам'яті знаходиться повністю під вашим контролем.
Якщо ви звільните менше байт, ніж було виділено, то байти, що залишилися, губляться (відбувається "витік" пам'яті, що динамічно розподіляється). Якщо ви звільните більше байт, ніж було виділено, то можете звільнити пам'ять, розподілену для іншої змінної, що може призвести до псування даних. У захищеному режимі звільнення більшого обсягу пам'яті, ніж було виділено, спричинить помилку порушення захисту (GP).
Припустимо, наприклад, що ви збираєтеся виділити пам'ять для одного або більше записів даних типу TCheck:
Кожна запис типу TCheck займає 50 байт, тому, якщо у вас є змінна ThisCheck типу PCheck, ви можете розподілити динамічний запис наступним чином:
а пізніше звільнити її за допомогою виклику:
Використання з процедурою GetMem функції SizeOf
Проте переконатися, що ви щоразу виділяєте і звільняєте той самий обсяг пам'яті, недостатньо. Ви повинні забезпечити розподіл правильного обсягу пам'яті. Припустимо, ви змінили визначення TCheck. Наприклад, якщо ви перевизначили TCheck.Payee як 50-символьний рядок замість 39-символьного, то не зможете отримати та звільняти достатньо пам'яті. Найнадійніше використовувати у програмі функцію SizeOf,наприклад:
Це не тільки забезпечує, що ви виділяєте і звільняєте один і той же обсяг, але гарантує, що при зміні розміру типу вашапрограма все одно виділятиме потрібну пам'ять.
Перевірка обсягу доступної пам'яті, що динамічно розподіляється
У Borland Pascal визначено дві функції, що повертають важливу інформацію про динамічно розподілену область пам'яті: MemAvail і MaxAvail.
Функція MemAvail повертає загальну кількість байт, доступних для розподілу динамічної пам'яті. Перед виділенням великого обсягу в пам'яті, що динамічно розподіляється, корисно переконатися, що такий обсяг пам'яті доступний.
Функція MaxAvail повертає розмір найбільшого доступного блоку безперервної пам'яті в області, що динамічно розподіляється. Спочатку при запуску програми MaxAvail дорівнює MemAvail, оскільки вся область пам'яті, що динамічно розподіляється, є доступною і безперервною. Після розподілу декількох блоків пам'яті простір в області, що динамічно розподіляється, швидше за все стане фрагментованим. Це означає, що між частинами вільного простору є розподілені блоки. Функція MaxAvail повертає розмір найбільшого вільного блоку.