Какво е "Memory Leak"?
Представете си, че сте написали страхотна програма, която обаче в един момент колкото по-дълго върви – толкова памет започва да консумира. Веднага ви става ясно, че нещо не е наред и бихте могли да бъдете почти сигурни, че причината за случващото се е т.нар. „Memory leak” („теч на памет“). Какво всъщност представляват тези „течове“? Условно можем да разделим memory leak-овете на три големи категории (подчертавам – условно). Всеки един от тези типове се отличава със собствено „поведение“ и изисква определени инструменти и подходи, за да се отстрани. Нека разгледаме кои са тези три случая.
Тип 1: Недостижими алокации
Това е класическата причина при C и C++, причиняваща memory leak. Някой е направил алокация на памет (заделил я е), но е забравил да извика "free" или "delete", за да я освободи след изпълнението на задачата.
Как да разпознаете този тип „теч“?
Ако пишете на C++ без да използвате повсеместно smart пойнтери за управление на продължителността на работа на паметта – тази причина трябва да е вашето първо предположение; Един от начините да откриете memory leak от такъв тип е чрез ASAN (AddressSanitizer – open source програмен инструмент на Google, който открива бъгове засягащи паметта като buffer overflow-ове и т.н.). Възможно е и чрез употреба на други „leak detector-и“ като Valgrind или heap tools. Някои алокатори могат да създадат heap профил, който съдържа всички неосвободени алокации. Ако наблюдавате leak-a определено време, през него ще „изтекат“ всички активни алокации, така че ще ви е лесно да ги забележите.
Тип 2: Неочаквано дълготрайни алокации
Това не са memory leak-ове в класическия смисъл на този термин, защото паметта евентуално може да бъде освободена, ако програмата успее да стигне до там преди да е изчерпала наличната памет, разбира се. Т.е. всичко може да е наред, но целия процес е съпроводен с необичайно висока консумация на памет. Има множество специфични причини за този тип „течове“, но най-често срещаните включват:
• Непредумишлено акумулиране на state върху глобална структура, например HTTP сървър, който поставя всеки request object, който получава, в глобален списък.
• Кеш без подходяща „трайност“. Например ORM кеш, който кешира всеки обект, който някога е бил зареден, който е бил активен по време на миграция, която зарежда всеки запис в таблица;
Как да разпознаете този тип memory leak?
• Ако пишете в garbage-collected runtime, това трябва да е вашето първо предположение.
• Сравнете heap размера, който се докладва от вашите GC статистики спрямо размера на паметта, който се докладва от операционната система. Ако вашият leak е в тази категория тези цифри ще са сходни.
За да намерите този тип memory leak използвайте heap профилиране или инструментите за dumping, които вашата работна среда ви осигурява.
Тип 3: Свободна, но неизползвана или неизползваема памет
Това е най-коварната категория, за която се сещам, но също така е много важно да я разбирате и да я откривате. Тя се проявява в „празнината“ която се образува „между“ паметта, която е обозначена като “свободна” от алокатора вътре във виртуална машина или runtime, и памет, която е обозначена като „свободна“ от операционната система. Heap фрагментирането е най-често срещаната причина, но съвсем не е единствената.
Как да разпознаете този тип „теч“?
Сравнете вашият heap размер, който е докладван от вашият алокатор спрямо RSS1, който се докладва от операционната система. Ако се прояви нарастваща разлика в числата, това означава, че имате точно този тип „теч“. Също така можете да рестартирате процесите на вашето приложение по-често или да опитате да използвате различни алокатори.
Ако имате добри познания по основи на програмирането и искате да ги надградите със знания като управление на паметта, advanced С++ class members, полиморфизъм и наследяване – тогава не губете време и запишете курса „C++ Advanced – септември 2018“. Не пропускайте тази възможност!