Confidențialitatea dumneavoastră e importantă pentru noi! Site-ul nostru folosește cookie-uri, pentru care avem nevoie de acceptul dumneavoastră. Vă rugăm să citiți aici politica de procesare a datelor personale și a utilizării cookie-urilor.
|
||||||||
|
web3tracer produce automat și profiluri de memorie. Pentru a evita problemele aferente diferențelor negative de memorie, am introdus 4 indicatori pentru consumul de memorie:
Pentru a vizualiza datele privind memoria, folosiți dropdown-ul "Event type" în KCachegrind. Puteți vedea mai jos cum arată un graf al memoriei maxime pentru scriptul exemplu recursiv:
Comparând cu codul sursă, ați putea observa ceva surprinzător: conținutul șirului de 3MB care este depozitat în memorie este generat de funcția str_repeat deci ne putem aștepta ca această funcție să genereze maximul de memorie utilizată. Totuși nu e așa.
Nu este, totuși, nici o eroare: motivul este că șirul de 3MB este alocat de operația de concatenare din funcția b(), iar funcția str_repeat() refolosește același spațiu de memorie pentru ieșirea sa, pentru că această ieșire e dealocată după executarea operației de concatenare.
Acesta este deasemenea motivul pntru care scriptul folosește 4MB de memorie pentru a produce un string de 3MB: o operație de concatenare folosește ca spațiu de memorie minim dimensiunea șirului sursă, plus de două ori dimensiunea incrementului, o remarcă interesantă.
Mergând mai departe cu exemplul, dacă analizăm profilul "Allocated memory", graful va arăta în genul:
Vom observa că b() nu are alocare internă (exclusivă) de memorie. Cum se poate, atuncisă adauge la maximul de memorie, dacă nu face nici o alocare? Pare lipsit de sens. Si este. Motivul este o limitare în PHP: nu există o modalitatea de a observa direct funcțiile de alocare/dealocare memorie, aceste cifre se calculează ca diferență între consumul de memorie la ieșirea și la intrarea în funcție. Deci ceea ce se întâmplă este: b() alocă de fiecare dată 1MB pentru concatenare (vezi paragraful de mai sus), dar apoi dealocă spațiul alocat de rezultatul lui str_repeat(), de exact aceeași dimensiune. Deși a fost 1MB alocat și apoi dealocat, nu există nici o metodă de a urmări această activitate, și astfel memoria alocată de B este raportată ca nulă.
Să mergem mai departe și să analiză timpii de execuție pentru funcția b():
Observăm că are un timp intern de 19ms, consumați fără dubii de operația de concatenare, dar funcția str_repeat care generează fragmentele concatenate, consumă doar 5ms. De ce ia concatenarea repetitivă de 4 ori ma mult timp decât dacă am genera șirul întreg într-un singur pas?
Răspunsul este că v-am mințit mai devreme. Ce se întâmplă cu un șir de X MB care este incrementat este următorul lucru: PHP alocă X+1 MB pentru rezultatul concatenării, în care copiază atât șirul inițial cât și apendicele. Asta înseamnă X+1 MB citiți, X+1 MB scriși. Apoi eliberează cei X+1 MB ai vechiului conținut și ai apendicelui. Totalul e următorul: în urma construirii șirului de 3MB, str_repeat citește 6MB și scrie 6MB, adică execută 12MB de operații pe memorie. Aceasta este exact diferența de 4x observată. Aceasta este și explicația mai lungă pentru care am adăugat memoria folosită și memoria eliberată într-o statistică separată, deși nu foarte util în acest caz pentru că ele sunt raportate 0 din cauza limitării menționate anterior.
Din câteva grafice simple, putem vedea multe din dedesubturile lucrului cu memoria în PHP. Este un lucru bun de știut că memoria nu e doar o resursă limitată, ci este corelată și cu timpul de execuție în moduri complexe. Și nu vom atinge în acest articol complexitățile garbage collector-ului, ale referințelor circulare sau cât timp poate să consume un banal unset(). Interpretarea profilurilor de memorie este o activitate mult mai complicată decât interpretarea timpilor de execuție. Sperăm că web3tracer, deși nu e perfect, vă va ajuta totuși să descoperiți multe din detaliile scripturilor dvs. cele ma complexe.
Spor la profilat! |