Витік пам'яті

Матеріал з Вікіпедії — вільної енциклопедії.
Перейти до навігації Перейти до пошуку

Витік пам'яті (англ. memory leak) — процес неконтрольованого зменшення обсягу вільної оперативної пам'яті або віртуальної пам'яті комп'ютера, пов'язаний з помилками в програмах, що вчасно не звільняють пам'ять від непотрібних даних, або з помилками системних служб контролю пам'яті.

Витік пам'яті найчастіше зустрічається у мовах програмування, які надають користувачеві можливість самому керувати пам'яттю комп'ютера.

Опис[ред. | ред. код]

Виконання наведеного коду на C++ призводить до витоку пам'яті:

/*1*/ int *pointer = NULL;
/*2*/ for (int i = 0; i < 10; i++) {
/*3*/   pointer = new int[100];
/*4*/ }
/*5*/ delete [] pointer;

На кожній ітерації циклу виділяється пам'ять для 100 цілих чисел типу int і адреса виділеної пам'яті записується у змінну pointer, затираючи адресу попереднього виділеного блоку пам'яті. У 5-му рядку відбувається видалення об'єкта, створеного на останній ітерації циклу. Усі попередні 9 об'єктів залишаються в динамічній пам'яті. До них неможливо ні отримати доступ з програми, ні видалити, оскільки немає змінних, які б зберігали їх адреси.

Небезпека[ред. | ред. код]

Динамічна пам'ять є обмеженим ресурсом. Керування динамічною пам'яттю програми зазвичай здійснюється бібліотекою мови програмування, яка сама працює поверх динамічної пам'яті, що надається операційною системою.

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

Способи запобігання[ред. | ред. код]

Існують різні способи запобігання витокам пам'яті.

Відмова від динамічної пам'яті[ред. | ред. код]

Наприклад, FORTRAN-77 повністю відмовляється від застосування механізмів динамічного розподілу пам'яті, що виключає подібні помилки, але істотно обмежує функціональність програм.

Розумні вказівники[ред. | ред. код]

Розумні вказівники дозволяють дещо узгодити час життя вказівника і час життя об'єкта, на який він посилається.

Прибирання сміття[ред. | ред. код]

Докладніше: Збирання сміття

Деякі мови програмування (наприклад, Оберон, Java, мови для CLI) надають засоби, що дозволяють автоматично звільняти невикористану пам'ять. Збирачі сміття вирішують також і проблему циклічних посилань, але збірка сміття є ресурсомісткою операцією. За використання подібних засобів доводиться розплачуватися швидкодією системи, і, головне, прибирання сміття вносить несподівані паузи у роботу програми, що неприпустимо в системах реального часу.

Прибирання сміття було винайдене Джоном Маккарті приблизно у 1959 році при розробці мови програмування LISP, структура якої робить вкрай складним ручне керування пам'яттю.

Перезапуск програми[ред. | ред. код]

У тих випадках, коли усунути витік пам'яті не є можливим, наприклад, при використанні коду, який надається у вигляді програмних модулів і виготовленого сторонніми розробниками, застосовують своєрідний спосіб ігнорування витоків. Код, схильний до витоків, розміщують в окремій програмі, а цю програму з потрібною періодичністю перезапускають. Запуски і перезапуски програми виконуються зовнішньою програмою, яка також подає вихідні дані і забирає результати. Оскільки при завершенні програми вся пам'ять, затребувана нею в операційної системи, повертається операційній системі, такий метод не дозволяє витокам набути катастрофічного характеру.

Витік інших ресурсів[ред. | ред. код]

Також існує помилка, що іменується витоком дескрипторів: захоплені дескриптори не повертаються операційній системі.

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

Виявлення витоків[ред. | ред. код]

Для професійних мов програмування існують спеціальні програми-профілювальники, що дозволяють виявити зокрема і витоки пам'яті.

Для деяких мов програмування існують статичні аналізатори коду, що виявляють елементи програми, потенційно здатні призводити до логічних помилок, зокрема і до витоку пам'яті. Примітивний варіант такого аналізатора реалізує практично будь-який компілятор мови високого рівня, у вигляді видачі так званих попереджень (warnings) — повідомлень про наявність у програмі конструкцій, які формально не порушують синтаксису мови, але потенційно помилкові.

Існують бібліотеки для налагодження використання пам'яті[en], які допомагають стежити за виділенням та звільненням пам'яті під час роботи програми.

Див. також[ред. | ред. код]