Повний посібник з витоків пам'яті в Linux

Останнє оновлення: 14/05/2026
Автор: Ісаак
  • Витоки пам'яті в Linux непомітно знижують продуктивність і зрештою запускають OOM Killer, якщо їх не виявити вчасно.
  • Такі інструменти, як top, htop, /proc, pmap та smem, дозволяють знаходити підозрілі процеси та аналізувати, як зростає споживання ними пам'яті.
  • Valgrind, memleax, gdb та інші профайлери допомагають визначити точне джерело витоків та помилок управління пам'яттю в коді.
  • Тестування навантаження, обмеження ресурсів та належні методи програмування є ключовими для запобігання серйозним витокам у виробничому середовищі.

витоки пам'яті в навчальних посібниках у Linux

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

У системі, яка завжди має бути доступною (сервери, виробничі контейнери, вбудовані пристрої тощо), витік пам'яті, який ніхто не контролює, схожий на бомбу уповільненої дії. Якщо ви не контролюєте, ви не виявляєте і не виправляєтеВ іншому випадку ви зіткнетеся з процесами, які завершує OOM Killer, випадковими збоями та розлюченими користувачами, які не зовсім розуміють, що сталося. У цьому посібнику ми детально, але зрозумілою мовою, розглянемо, як виявляти та аналізувати витоки пам'яті в Linux за допомогою таких базових інструментів, як верх/верх навіть досвідчені профайлери, такі як Valgrind, memleax або gdb, на додаток до таких комунальних послуг, як /proc, pmap або smem.

Що таке витік пам'яті в Linux і чому він такий небезпечний?

Витік пам'яті відбувається, коли програма Він резервує системну пам'ять (купу, структури, буфери тощо) і ніколи її не звільняє. коли це більше не потрібно. У мовах програмування, таких як C або C++, це зазвичай перекладається у виклики функції malloc, calloc, new які не супроводжуються відповідними free o deleteабо в посиланнях, які застрягають і унеможливлюють повторне використання цієї пам'яті.

На практиці процес продовжує відбуватися у звичайному режимі, але Споживання пам'яті поступово збільшується З кожним запитом, кожним робочим циклом або кожним новим завданням це зростання може бути дуже повільним (порядку кількох КБ або МБ на день), що робить його особливо важким для виявлення з першого погляду без належного моніторингу.

Наслідки ігнорування цієї проблеми очевидні: зниження продуктивності, постійні перезавантаження, величезні затримкиІ в певний момент системі закінчується доступна пам'ять. Ось тут-то й Вбивця OOM ядра Linux, який завершує процеси, що споживають найбільше пам'яті (або ті, які алгоритм вважає найбільш витратними), щоб запобігти збою всієї системи.

Таку поведінку зазвичай найкраще видно на графіках моніторингу: RSS-пам'ять процесу Він поступово підвищується протягом кількох днів Доки раптово не почнеться його падіння, коли OOM Killer завершить його роботу, і служба перезапуститься. Якщо ніхто не проаналізує ці події, витік залишиться, і цикл повториться.

Ось чому ключово зрозуміти, що Витоки пам'яті — це не лише проблема кодуале також і функціонування та спостережуваності: необхідно знати, як виявляти їх у виробництві, співвідносити їх із системними подіями та мати інструменти для їх аналізу як у процесах, що вже запущені, так і в тестових середовищах.

Типові причини та чіткі симптоми витоку пам'яті

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

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

Симптоми, які повинні вас насторожити, цілком впізнавані, якщо ви знаєте, на що звертати увагу. Найбільш очевидним є те, як Пам'ять процесу (RES/RSS) постійно зростає навіть якщо робоче навантаження залишається стабільним. Це як спостерігати за падінням показника рівня палива в припаркованому автомобілі.

Ще один типовий ефект – це поступове погіршення продуктивностіСистема починає використовувати swap, затримки різко зростають, запити, які раніше були швидкими, стають нескінченними, і решта процесів хоста також страждають, навіть якщо вони не є прямими винуватцями.

Нарешті, з'являється найдраматичніший симптом: неочікувані збої процесів або системиЯдро, не маючи пам'яті для виділення, активує функцію Out-of-Memory Killer та завершує процеси. Якщо процес, який завершує збій, є ізольованим мікросервісом, це все ще незначна проблема, але якщо процес, який завершує збій, є, наприклад, базою даних або менеджером черг, наслідки можуть бути дуже серйозними.

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

Базовий моніторинг за допомогою top та htop

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

  Як отримати доступ до розділів Linux з Windows 11: WSL, мережа та програми

У більшості дистрибутивів ви можете встановити htop Легко за допомогою менеджера пакетів. На системах на базі Debian достатньо чогось на кшталт цього:

sudo apt install htop

Після встановлення, під час запуску htop Ви побачите інтерактивне представлення процесів з кольорами, індикаторами процесора та пам'яті, а також різними стовпцями. Ключові колонки для виявлення витоків Це резидентна пам'ять та віртуальна пам'ять процесу:

- РЕС / РСС (Розмір резидентного набору): фізична пам'ять, яку процес наразі має в оперативній пам'яті.
- ВІРТ (Віртуальна пам'ять): загальний обсяг віртуальної пам'яті, виділеної процесом (включає відображену та потенційно підкачану пам'ять).
- %MEM: відсоток фізичної оперативної пам'яті, яку споживає процес, від загального обсягу системної оперативної пам'яті.

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

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

Глибше занурення у файлову систему /proc

Щоб перейти від поверхневого погляду до більш витонченого аналізу, Linux розкриває детальна інформація про кожен процес у псевдофайловій системі /procКожен PID має свій власний каталог усередині /procІ там можна перевірити всілякі показники, включаючи ті, що пов'язані з пам'яттю.

Класичною точкою входу є файл /proc//status, де ви знайдете такі поля, як VmRSS, VmSize або VmDataВи можете переглянути їх за допомогою простого:

cat /proc/<pid>/status

У цьому виводі найцікавішими полями для виявлення витоків пам'яті є:

- VmRSS: резидентна пам'ять (у КБ), яку процес має в оперативній пам'яті на даний момент.
- Розмір віртуальної машини: загальний обсяг віртуальної пам'яті, пов'язаної з процесом (включає все, що було відображено).
- VmData: пам'ять сегментів даних, де зазвичай знаходяться динамічні структури та купи, область, дуже схильна до витоків пам'яті.

Практична ідея полягає в тому, щоб постійно перевіряти ці значення. через рівні проміжки часу (вручну або за допомогою скриптів) та спостерігайте, чи вони мають стабільну тенденцію до зростання. Якщо ви бачите, що VmRSS та, особливо VmData, зростають без зменшення в періоди низького навантаження, це досить вагома ознака того, що програма має витік пам'яті.

Плюс statusв /proc/ У вас є інші цікаві файли для аналізу карти пам'яті, такі як maps o smaps, хоча вони більш багатослівні та часто використовуються разом з іншими інструментами, такими як pmap щоб зробити інформацію більш читабельною.

Аналіз карти пам'яті процесу за допомогою pmap

Утиліта pmap Це дуже корисна команда для отримання організованого вигляду карти пам'яті певного процесу. По суті, вона показує, які діапазони адрес відобразив процес, розмір кожного діапазону, його дозволи та якому файлу, бібліотеці чи типу пам'яті він відповідає.

Щоб скористатися ним, просто запустіть:

pmap

У виводі ви побачите рядки з початковою адресою, розміром, правами доступу (читання, запис, виконання) та походженням (наприклад, основний виконуваний файл, спільна бібліотека, така як libcанонімні області, купа тощо). Анонімні області пам'яті та зона купи Саме вони зазвичай дають підказки щодо витоків пам'яті.

Практичний спосіб відстеження прогресу – це повторення. pmap час від часу перевіряти, чи певні сегменти (особливо анонімні, пов'язані з купою) вони не перестають ростиВи також можете фільтрувати або підсумовувати вивід, наприклад:

pmap <pid> | grep total

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

smem: розрізнення спільної пам'яті та фактичного використання кожним процесом

Такі інструменти, як top, htop або pmap, підраховують всю пам'ять, на яку посилається процес, але вони не чітко відокремлюють пам'ять, яка дійсно є виключною для цього процесу, від пам'яті, що використовується спільно з іншими (наприклад, спільні бібліотеки). Ось тут і вступає в гру [наступне]. смем, спеціальна утиліта для забезпечення точнішого уявлення.

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

Деякі з найважливіших показників, які ви побачите у виводі SMEM:

- військовий корабель США (Унікальний розмір набору): пам'ять, яка використовується лише цим процесом; якщо процес зникає, ця частина пам'яті повністю звільняється.
- PSS (Пропорційний розмір набору): розподіляє спільну пам'ять між усіма процесами, які її використовують, пропонуючи досить справедливе пропорційне уявлення про фактичний розмір пам'яті.
- RSS (Розмір резидентного набору): Резидентна пам'ять, як і в інших інструментах, але представлена ​​разом із вищезазначеним для порівняння.

Під час запуску чогось на кшталт smem -k Ви отримаєте таблицю зі стовпцями PID, користувача, команди та використання пам'яті. Цікаво, з точки зору витоків пам'яті, зосередитися головним чином на військовий корабель СШАоскільки вона відображає власну пам'ять програми, саме там зазвичай з'являються найсерйозніші витоки.

Якщо ви залишаєте smem періодично запущеним (або інтегруєте його в скрипти моніторингу) і бачите, що USS певного процесу З часом воно продовжує зростатиНавіть коли навантаження не зростає, така поведінка дуже свідчить про витік пам'яті в окремій частині цього процесу, що відповідає за пам'ять.

  Як перейти з Windows на Linux за допомогою Operase: повний посібник без втрати будь-яких даних

memleax: автоматичне виявлення витоків у запущених процесах

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

memleax в основному розповсюджується у вигляді пакетів. .rpm y .debВін доступний у деяких репозиторіях, таких як для Arch Linux та FreeBSD. На системах на базі Debian поширеним способом його встановлення є завантаження пакета з офіційного репозиторію GitHub, а потім використання dpkg Щоб встановити його, вирішіть залежності за допомогою менеджера пакетів.

Після встановлення ви можете підключити memleax до процесу за допомогою:

sudo memleax -p

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

Типовий вивід показує лінії стилю malloc(128) = 0x... а потім, у разі виникнення проблеми, повідомлення, що вказують на щось подібне виявлено витік пам'яті для певного блоку. Ця інформація дуже корисна, оскільки вона показує, що, хоча процес все ще активний і працює, є блоки, які осиротівають.

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

Використання gdb для глибокого аналізу пам'яті процесу

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

Для початку ви встановлюєте gdb з репозиторіїв вашого дистрибутива (наприклад, за допомогою sudo apt install gdb (на Debian/Ubuntu), а потім приєднати його до процесу за допомогою:

sudo gdb -p

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

Крім того, з gdb можна викликати такі функції libc, як malloc_stats() через:

(gdb) call malloc_stats()

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

Ще один потужний підхід полягає в розміщенні точки зупинки у функціях, таких як malloc o free спостерігати в режимі реального часу за поведінкою коду: скільки разів він резервує, в які моменти звільняє пам'ять, які шляхи коду роблять багато розподілів, але мало звільняють пам'яті… Хоча це вимагає більшої експертизи в налагодженні, це прямий спосіб знайти точне джерело витоків.

Valgrind: класичний профайлер пам'яті в Linux

Якщо ми говоримо про виявлення витоків пам'яті в середовищах Linux, неможливо не згадати ВальгріндValgrind — це більше, ніж просто інструмент, фреймворк для налагодження та профілювання який включає кілька модулів, найвідомішим та найвикористовуванішим з яких є Memcheck, розроблений спеціально для виявлення проблем із пам’яттю.

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

Серед типів помилок, які може виявити Memcheck, є: Неініціалізоване використання пам'яті, читання/запис після звільнення пам'яті, незаконний доступ до областей пам'яті, що не належать програмі, і, звичайно ж, витоки пам'яті різних типів (блоки точно втрачені, можливо втрачені, все ще досяжні тощо).

Його базове використання відносно просте. Ви компілюєте свою програму з символами налагодження (наприклад, з -g o -gstabs), а потім ви запускаєте його під Valgrind з чимось на кшталт:

valgrind --tool=memcheck --leak-check=full -v ./tu_programa

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

Якщо ви навмисно вводите malloc без відповідного freeабо будь-який інший шаблон витоку, і ви знову запустите бінарний файл за допомогою Valgrind, ви побачите у виводі ЗВЕДЕННЯ КУПИ що вказує на обсяг пам’яті, що залишається «використаною» після закриття програми. У розділі ЗВЕДЕННЯ ПРО ВИТОКИ Рядки на кшталт «definitely lost» (точно втрачено) з’являться з байтами та блоками, які не були вивільнені.

Крім того, Memcheck точно вам скаже де відбувся розподіл, що спричинив витікВи побачите трасування викликів із функціями, вихідними файлами та номерами рядків. Наприклад, воно може показувати, що malloc у певному рядку вашого файлу .c Це створило блок, який так і не був випущений, одразу проливаючи світло на джерело проблеми.

Valgrind також дуже ефективно виявляє інші класичні помилки: наприклад, незаконні записи на пам'ять (наприклад, запис за адресою 0 або за межі масиву), використання неініціалізованих змінних (відображення повідомлень типу «Умовний перехід або переміщення залежить від неініціалізованого значення(й)») або неправильні релізи (як зробити free на вказівнику, який не походить з mallocабо двічі відпустити той самий блок).

  NTFS проти FAT32: який з них використовувати в кожній ситуації?

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

Інші профайлери пам'яті: gperftools, Massif та інші

Хоча Valgrind-Memcheck часто є першим вибором, існують інші інструменти профілювання, які дуже добре доповнюють аналіз витоків пам'яті та шаблонів використання. Один з них - gperftools (раніше Google Performance Tools), що включає профайлер купи здатний записувати використання пам'яті з плином часу та створювати візуальні звіти (наприклад, з pprof), які показують, які частини коду резервують більше пам'яті.

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

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

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

Проактивні стратегії: навантажувальне тестування, обмеження та найкращі практики

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

Перш за все, це має великий сенс зробити навантажувальне та стрес-тестування в передвиробничих середовищах які є максимально реалістичними. Такі інструменти, як Apache JMeter, Locust, stress Подібні інструменти дозволяють імітувати одночасну роботу користувачів, інтенсивні запити або тривалі сценарії. Під час цих тестів слід ретельно стежити за показниками пам'яті (RSS, купа тощо), щоб побачити, чи є якісь проблеми. повільне, але безперервне зростання.

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

На рівні конфігурації системи Linux пропонує механізми для обмежити вплив процесу, який «виходить з-під контролю». Наприклад, с ulimit Ви можете встановити обмеження пам'яті для процесів, запущених певним користувачем, обмежуючи розмір його віртуальної пам'яті. Щось на кшталт ulimit -v <kilobytes> Це запобіжить споживанню всієї оперативної пам'яті хоста однією службою.

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

Зрештою, з точки зору розвитку, найкращим захистом залишається Напишіть код, який добре керує пам'яттю з самого початку.У C/C++ це означає суворе ставлення до кожного malloc/new та відповідний йому free/delete, використовувати шаблони RAII, розумні вказівники (наприклад std::shared_ptr, std::unique_ptrта уникайте непотрібних посилань. Ви також можете звернутися до Підручник з іржі Для безпечних з точки зору пам'яті альтернатив. У мовах програмування зі збирачами сміття (Java, C#, Go, Python, JavaScript тощо) також легко спричинити псевдовитоки, якщо зберігати активні посилання на об'єкти, які вам більше не потрібні.

Інструменти статичний аналіз, такий як cppcheck, SonarQube Ці інструменти та методи допомагають виявляти підозрілі шаблони коду під час розробки. Додайте до цього ретельні перевірки коду, модульні тести, що перевіряють поведінку під навантаженням, та регулярні запуски Valgrind або інших профайлерів у середовищах непреривної інтеграції, і шанси на те, що серйозна вразливість потрапить у продакшн, значно зменшуються.

Зрештою, контроль витоків пам'яті в Linux передбачає поєднання безперервний моніторинг, потужні діагностичні інструменти та належні методи програмуванняЗа допомогою top, htop, /proc, pmap та smem ви можете знаходити підозрілі процеси; за допомогою memleax та gdb ви можете виконувати перевірки в реальному часі; за допомогою Valgrind, gperftools або Massif ви можете ретельно налагоджувати та профілювати; а за допомогою навантажувального тестування, системних обмежень та добре написаного коду ви можете запобігти вибуху проблеми в найневідповідніший момент.

Посібник з Apache JMeter
Пов'язана стаття:
Повний посібник з Apache JMeter для тестування продуктивності