Шта су цурења меморије и како их можете поправити?

Poput mozga koji je ključan za ljudski život, memorija je podjednako vitalna za računare. Vaš sistem neće moći efikasno da obavlja zadatke ako nema dovoljno RAM-a.

Nedostatak RAM-a i razni drugi problemi sa memorijom često su rezultat curenja memorije. U ovom tekstu ćemo objasniti kako možete otkriti curenje memorije i uspešno ga sanirati.

Ali pre toga, hajde da detaljnije razjasnimo šta je curenje memorije i zašto je važno da ga rešimo.

Šta su curenja memorije?

Zamislite parking koji se nalazi tik do tržnog centra, gde su parkirani svi automobili, bez obzira da li su kupci završili kupovinu ili ne. Vremenom, neće biti više slobodnog prostora za parkiranje novih vozila, što će dovesti do saobraćajnih gužvi i smanjiti ukupnu efikasnost tržnog centra.

Izvor slike: prateeknima.medium.com

Ista situacija se dešava i sa računarima!

Računarske aplikacije, poput automobila na parkingu, mogu zaboraviti da oslobode memoriju koju su koristile kada im više nije potrebna. Ovo opterećuje vašu memoriju i onemogućava nesmetano izvršavanje novih zadataka, što dovodi do uobičajene greške u memoriji koja se naziva curenje memorije.

Primer koda koji ilustruje curenje memorije:

void memory_allocation() {
    int *ptr = (int*)malloc(sizeof(int));
}

Gornji isečak C koda dodeljuje određenu količinu memorije za celobrojnu promenljivu i dodeljuje njenu memorijsku lokaciju pokazivaču ‘ptr’. Međutim, ne postoji kod koji oslobađa tu memoriju, što rezultira curenjem memorije.

def infinite_rec():
    return infinite_rec()

U gornjem Python kodu, nema osnovnog uslova za zaustavljanje funkcije. Stoga, ovaj kod dovodi do prekoracenja steka i curenja memorije.

Uobičajeni uzroci curenja memorije

Neopreznost programera

Glavni razlog za curenje memorije je nepažnja programera.

Programeri često alociraju podatke u memoriju, ali ponekad zaborave da je oslobode kada im više nije potrebna. S vremenom, ovo zauzima celokupnu memoriju i ne ostavlja prostor za buduće zadatke, što dovodi do pojave greške „curenja memorije“.

Programski jezici

Korišćenje programskih jezika koji nemaju ugrađen sistem za upravljanje memorijom može izazvati curenje memorije.

Programski jezici kao što je Java imaju ugrađene sakupljače smeća koji automatski upravljaju memorijom.

Međutim, na primer, C++ nema ugrađen sakupljač smeća. Ovde programer mora ručno da upravlja memorijom, što dovodi do curenja memorije kada god se zaboravi ručno osloboditi memorija.

Prekomerna upotreba keša

Često korišćeni zadaci, podaci ili aplikacije se keširaju radi bržeg pristupa.

Ovo može dovesti do greške u vidu curenja memorije ukoliko se keširane stavke ne brišu kada su zastarele ili kada više nisu u skladu sa vašim trenutnim obrascima upotrebe.

Upotreba globalnih promenljivih

Globalne promenljive čuvaju dodeljene podatke tokom čitavog trajanja aplikacije. Stoga, korišćenje velikog broja globalnih promenljivih troši mnogo memorije tokom dužeg vremenskog perioda, što može dovesti do curenja.

Neefikasne strukture podataka

Programeri često kreiraju sopstvene strukture podataka kako bi ostvarili prilagođene funkcionalnosti. Međutim, greške u vezi sa curenjem memorije se javljaju kada te strukture podataka ne mogu osloboditi korišćenu memoriju.

Nezatvorene veze

Nezatvaranje datoteka, baza podataka, mrežnih veza itd. nakon njihove upotrebe, takođe može dovesti do grešaka povezanih sa curenjem memorije.

Posledice curenja memorije

Slabije performanse – primetićete postepeno opadanje performansi vaše aplikacije ili sistema kako se curenje memorije nagomilava. To je zato što neće biti dovoljno dostupne memorije za izvršavanje zadataka, što će usporiti rad vaše aplikacije.

Rušenje aplikacija – aplikacijama ponestaje memorije kako curenje memorije raste. U jednom trenutku, bez dostupne memorije, program se ruši, što može dovesti do gubitka podataka i prestanka rada aplikacije.

Sigurnosni propusti – nepravilno brisanje osetljivih podataka, kao što su lozinke, lični podaci ili poverljive informacije, iz memorije nakon njihove upotrebe, izlaže te podatke napadačima tokom curenja memorije.

Iscrpljivanje resursa – aplikacije zauzimaju više prostora u RAM-u kada im ponestane memorije zbog curenja. To povećava potrošnju resursa i smanjuje ukupne performanse sistema.

Kako otkriti curenje memorije?

Ručna inspekcija koda

Pregledajte izvorni kod da biste pronašli mesta gde je memorija dodeljena, ali nije oslobođena nakon upotrebe. Potražite promenljive i objekte u kodu koji koriste memoriju, ali je ne oslobađaju kada im više nije potrebna.

Takođe, obratite posebnu pažnju na glavne izvore skladištenja podataka, odnosno, osigurajte da strukture podataka pravilno upravljaju dodeljenom memorijom.

Statička analiza koda

Različiti dobro dizajnirani alati za statičku analizu analiziraju izvorni kod kompajlera i otkrivaju slučajeve curenja memorije.

Oni prate uobičajene obrasce, pravila i greške u vašem kodu kako bi predvideli curenje memorije, čak i pre nego što se dogodi.

Alatke za dinamičku analizu

Ove alatke koriste dinamički pristup za analizu koda tokom izvršavanja i otkrivanje curenja memorije.

Alati za dinamičku analizu ispituju ponašanje objekata, funkcija i njihovo korišćenje memorije tokom vremena izvršavanja. Stoga su ovi alati veoma precizni u otkrivanju curenja memorije.

Alatke za profilisanje

Alatke za profilisanje vam daju uvid u to kako aplikacija koristi memoriju.

Vi, kao programer, možete koristiti ove informacije da analizirate korišćenje memorije programa i optimizujete tehnike upravljanja memorijom kako biste sprečili pad aplikacija i probleme sa degradacijom memorije.

Biblioteke za otkrivanje curenja memorije

Neki programski jezici nude ugrađene biblioteke ili biblioteke nezavisnih proizvođača za otkrivanje curenja memorije u vašem programu.

Na primer, Java ima sakupljač smeća koji se bavi memorijom, dok C++ nudi CrtDbg za upravljanje memorijom.

Takođe, specijalizovane biblioteke poput LeakCanary, Valgrind, YourKit itd., rešavaju curenje memorije u različitim tipovima aplikacija.

Kako popraviti curenje memorije?

Identifikujte curenje memorije

Da biste popravili curenje memorije, prvo ga morate otkriti.

Možete izvršiti ručnu inspekciju ili koristiti neki automatizovani alat kako biste proverili da li aplikacija ima curenje memorije. Možete isprobati druge metode za otkrivanje curenja memorije koje su pomenute iznad, kako biste locirali problem.

Identifikujte objekte koji uzrokuju curenje

Nakon što potvrdite da aplikacija ima curenje memorije, treba da potražite objekte i strukture podataka koji su uzrok curenja. Shvatite kako se memorija alocira za njih i gde bi trebalo da je oslobode.

Kreirajte test primere

Sada ste suzili tačno mesto curenja memorije. Zato, kreirajte test primer kako biste bili sigurni da ste ispravno identifikovali izvor curenja memorije i da biste potvrdili da curenje nestaje kada popravite te konkretne objekte.

Popravite kod

Dodajte kod za oslobađanje memorije kako biste oslobodili memoriju koju su blokirali identifikovani problematični objekti. Ako kod već postoji, ažurirajte ga kako biste bili sigurni da pravilno raspoređuje korišćenu memoriju.

Ponovo testirajte

Ponovo koristite alate za otkrivanje curenja ili automatizovane testove kako biste proverili da li aplikacija radi kako je predviđeno i da nema blokade memorije.

Takođe, testirajte performanse i funkcionalnost aplikacije kako biste bili sigurni da ažuriranje koda ne utiče na druge aspekte aplikacije.

Najbolje prakse za sprečavanje curenja memorije

Budite odgovoran programer

Trebalo bi da budete svesni oslobađanja korišćene memorije ili otpuštanja memorijskih pokazivača dok pišete sam kod. Ovo će značajno smanjiti probleme sa curenjem memorije.

Sećate se koda ispod? Kao što je pomenuto na početku članka, ne postoji deo koda za dealokaciju memorije, pa to dovodi do curenja memorije.

void memory_allocation() {
    int *ptr = (int*)malloc(sizeof(int));
}

Evo kako vi, kao programer, možete osloboditi memoriju.

delete ptr;

Koristite opremljene programske jezike

Programski jezici kao što su Java ili Python koriste ugrađene biblioteke za upravljanje memorijom, kao što su sakupljači smeća, za automatsko rešavanje curenja memorije.

Iako možete prevideti nekoliko slučajeva, ovi ugrađeni alati se time bave, sprečavajući potencijalna curenja memorije.

Stoga, preporučujemo vam da koristite programske jezike u kojima je upravljanje memorijom ugrađeno.

Kružne reference

Izbegavajte kružne reference u svom programu.

Kružne reference prate zatvorenu petlju objekata koji se odnose jedni na druge. Na primer, objekat a se odnosi na b, objekat b se odnosi na c, a objekat c se ponovo odnosi na a, bez kraja u petlji. Dakle, kružne reference vode do beskonačne petlje, uzrokujući curenje memorije.

Minimizirajte upotrebu globalnih promenljivih

Trebalo bi da izbegavate upotrebu globalnih promenljivih ako ste zabrinuti za efikasnost memorije. Globalne promenljive troše vašu memoriju tokom celog trajanja aplikacije, što nije dobra praksa u upravljanju memorijom.

Zato, pređite na lokalne promenljive. One su efikasnije u pogledu memorije jer oslobađaju memoriju kada se poziv funkcije završi.

Globalne promenljive izgledaju ovako, ali ih koristite samo kada je to neophodno.

int x = 5 // Globalna promenljiva
void func(){
    print(x)
}

Ali, koristite lokalne promenljive na sledeći način:

void func(){
    int x = 5 // Lokalna promenljiva
    print(x)
}

Ograničite keš memoriju

Postavite ograničenje memorije koju keš može koristiti. Ponekad, svi zadaci koje obavljate u sistemu budu gurnuti u keš memoriju, a ta akumulirana keš memorija može dovesti do curenja memorije.

Dakle, ograničavanje keša može sprečiti curenje memorije.

Dobro testirajte

Uključite testove curenja memorije u vašu fazu testiranja.

Kreirajte automatizovane testove i pokrijte sve ekstremne slučajeve da biste otkrili curenje memorije pre nego što pustite kod u produkciju.

Opremite alate za praćenje

Koristite alate za automatsko profilisanje kako biste nadgledali upotrebu memorije. Redovno praćenje potrošnje memorije pomaže vam da identifikujete potencijalna curenja i da ih popravite preventivno.

Visual Studio profiler, .NET Memory Profiler i JProfiler su neki od dobrih alata u ovom kontekstu.

Zaključak

Efikasno upravljanje memorijom je ključno za postizanje vrhunskih performansi aplikacije, a curenje memorije se ne može zanemariti u tom kontekstu. Za efikasno upravljanje memorijom, trebalo bi da se bavite problemom curenja memorije i da sprečite njihovo pojavljivanje u budućnosti. Ovaj članak objašnjava kako to možete postići.

Pokazali smo vam različite metode za otkrivanje curenja memorije, proverene korake za njihovo popravljanje i prakse koje možete pratiti da biste izbegli curenje memorije u budućnosti.

Zatim, možete istražiti kako da popravite grešku „nedostatak memorije“ u Windows-u u roku od 5 minuta.