Cum se detectează o scurgere de memorie

Atunci când dezvoltăm aplicații mari care manipulează cantități mari de informații în primul rând în timpul depanării, apare problema detectării unei alocări incorecte a memoriei. Problema constă în faptul că dacă alocăm o bucată de memorie și apoi nu eliberăm tot volumul alocat, atunci se formează blocuri de memorie care sunt marcate ca fiind ocupate, dar de fapt nu sunt folosite. Cu un program lung, astfel de blocuri se pot acumula, ceea ce duce la un consum semnificativ de memorie.

Cum se detectează o scurgere de memorie

Atunci când dezvoltăm aplicații mari care manipulează cantități mari de informații în primul rând în timpul depanării, apare problema detectării unei alocări incorecte a memoriei. Problema constă în faptul că dacă alocăm o bucată de memorie și apoi nu eliberăm tot volumul alocat, atunci se formează blocuri de memorie care sunt marcate ca fiind ocupate, dar de fapt nu sunt folosite. Cu un program lung, astfel de blocuri se pot acumula, ceea ce duce la un consum semnificativ de memorie.

Pentru a detecta astfel de erori, a fost creat software specializat (cum ar fi BoundsChecker de la Numega), dar este mai convenabil să se integreze un mecanism de detectare a scurgerilor în proiectele dvs. Prin urmare, metoda ar trebui să fie simplă și, în același timp, posibilă ca universală. În plus, nu vreau să rescrii de ani de zile megabytele acumulate de cod scrise și depanate cu mult înainte de a vă gândi să vă protejați de erori. Astfel, standardizarea este adăugată la lista cerințelor, adică trebuie să integrați cumva protecția erorilor în codul standard.

Soluția propusă se bazează pe supraîncărcarea noilor operatori de alocare a memoriei și pe ștergerea acestora. Și vom supraîncărca operatorii globali noi | ștergeți, deoarece rescrierea acestor operatori pentru fiecare clasă dezvoltată mai devreme ar fi un proces foarte laborios. astfel după suprasarcină, va trebui doar să urmărim alocarea memoriei și, prin urmare, să o eliberăm în momentul în care programul este terminat. Toate neconcordanțele sunt o greșeală.

punerea în aplicare

Proiectul este scris în Visual C ++, dar rescrierea acestuia la orice alt dialect C ++ nu va fi prea dificil. În primul rând, trebuie să înlocuiți noii operatori standard și să ștergeți astfel încât să funcționeze în toate proiectele. Prin urmare, în stdafx.h, adăugați fragmentul următor:

După cum puteți vedea, depășirea instrucțiunilor apare în blocul # ifdef / # endif. Acest lucru ne protejează codul de la afectarea lansării programului compilat. Probabil ați observat că acum operatorul nou are trei parametri în loc de unul. Doi parametri suplimentari conțin numele fișierului și numărul liniei în care este alocată memoria. Acest lucru este convenabil pentru detectarea unui anumit loc în care apare o eroare. Cu toate acestea, codul proiectelor noastre se referă încă la operatorul nou, care ia un parametru. Pentru a corecta această neconcordanță, trebuie să adăugați fragmentul următor

Acum toți noii operatori vor fi chemați cu trei parametri, iar parametrii lipsă vor fi înlocuiți de un preprocesor. Desigur, funcțiile goale depășite nu ne vor ajuta în nimic, deci să le adăugăm un cod:

Pentru a completa imaginea, trebuie să redefiniți operatorii noi [] și să ștergeți [], dar nu există diferențe semnificative aici - creați!

Atingerea finală este de a scrie funcțiile AddTrack () și RemoveTrack (). Pentru a crea o listă a blocurilor de memorie folosite, vom folosi instrumentele STL standard:

Înainte de terminarea programului, lista noastră allocList conține referințe la blocurile de memorie care nu au fost eliberate. Tot ce trebuie să faceți este să aduceți aceste informații undeva. În proiectul nostru, vom lista zonele de memorie neocupate în fereastra de ieșire a mesajelor de depanare Visual C ++:

Sper că acest proiect va face ca foile de bug-uri să fie mai scurte, iar programele sunt mai stabile. Mult noroc!

#include
#include

folosind namespace std;

#ifndef _ALLOC_
#define _ALLOC_
typedef struct adresa DWORD;
Dimensiune DWORD;
fișierul cu caractere [64];
Linia DWORD;
> ALLOC_INFO;

listă tippedef AllocList;

AllocList * allocList;
# endif

void AddTrack (DWORD addr, DWORD asize, const char * fname, DWORD lnum)
ALLOC_INFO * info;

dacă (! allocList) allocList = new (AllocList);
>

info = nou (ALLOC_INFO);
info-> adresa = addr;
strncpy (info-> fișier, fname, 63);
info-> linie = lnum;
info-> size = asize;
allocList-> inserați (allocList-> begin (), * info);
>;

void RemoveTrack (DWORD addr)
AllocList :: iterator i;

dacă (! allocList)
return;
pentru (i = allocList-> begin (); i! = allocList-> end (); i ++)
dacă ((i) -> adresa == addr)
allocList-> șterge (i);
pauză;
>
>
>;
void DumpUnfreed ()
AllocList :: iterator i;
DWORD totalSize = 0;
char buf [1024];

pentru (i = allocList-> begin (); i! = allocList-> end (); i ++)
sprintf (buf, "% -50s: \ tLINE., \ tADDRESS.
(i) -> fișier, (i) -> linie, (i) -> adresa, (i -> dimensiune);
OutputDebugString (buf);
totalSize + = (i) -> dimensiune;
>
sprintf (buf, "--------------------------------------------- ----- ");
OutputDebugString (buf);
sprintf (buf, Total Unfreed: bytes, totalSize);
OutputDebugString (buf);
>;
//.

inline void * __cdecl operator nou (mărime nesemnată int, const char * fișier, int linie)
void * ptr = (void *) malloc (dimensiune);
AddTrack ((DWORD) ptr, mărime, fișier, linie);
retur (ptr);
>;

inline void operator __cdecl șterge (void * p)
RemoveTrack ((DWORD) p);
liber (p);
>;

#ifdef _DEBUG
#define DEBUG_NEW nou (__ FILE__, __LINE__)
#else
#define DEBUG_NEW nou
# endif
#definește noua DEBUG_NEW


schimbat:
adresele de tip (* i) -> adresa de pe adresa i->;
allocList-> remove ((* i)); pe allocList-> șterge (i); deoarece în lista, atunci când sunați remove () la linia if (* _First == _Val), nu este posibilă compararea structurilor și compilatorul este obfuscated

#ifndef
#define
#endif nu ajută, cum pot rezolva asta?

Articole similare