Denna artikel beskriver hur heap-profileraren
Heapen är minnesregionen som allokeras med funktioner som malloc. Den växer enligt efterfrågan och är vanligen den största minnesregionen i ett program. Stacken är där alla lokala data för funktioner lagras. Detta inkluderar de ”automatiska” variablerna i C och returadressen för subrutiner. Stacken är vanligen mycket mindre och mycket mer aktiv än heapen. Vi kommer inte explicit tänka närmare på stacken eftersom
Det är också användbart att berätta för
Din kommandorad bör därför se ut något i stil med:
valgrind --tool=massif --depth=5 --alloc-fn=g_malloc --alloc-fn=g_realloc --alloc-fn=g_try_malloc \
--alloc-fn=g_malloc0 --alloc-fn=g_mem_chunk_alloc swell-foop
Grafiskt utdata för
Textfilen är arrangerad som en hierarki av avsnitt, högst upp är en lista över de värsta minnesanvändarna arrangerade i ordning efter sjunkande utrymmestid. Under detta är vidare avsnitt som vardera delar upp resultaten i större detalj allt efter att du fortsätter ner för anropsstacken. För att illustrera detta kommer vi visa utdata för kommandot ovan.
Bilden ovan visar typiskt postscript-utdata från
Högst upp på grafen ser vi ett stort gult band märkt gdk_pixbuf_new. Detta verkar vara en ideal kandidat för optimering, men vi kommer behöva använda textfilen för att få reda på vad som anropar gdk_pixbuf_new. Början på textfilen kommer se ut något i stil med detta:
Command: ./swell-foop
== 0 ===========================
Heap allocation functions accounted for 90.4% of measured spacetime
Called from:
28.8% : 0x6BF83A: gdk_pixbuf_new (in /usr/lib/libgdk_pixbuf-2.0.so.0.400.9)
6.1% : 0x5A32A5: g_strdup (in /usr/lib/libglib-2.0.so.0.400.6)
5.9% : 0x510B3C: (within /usr/lib/libfreetype.so.6.3.7)
3.5% : 0x2A4A6B: __gconv_open (in /lib/tls/libc-2.3.3.so)
Raden med ”=”-tecknen indikerar hur långt ner för stackspåret vi är, i detta fall på toppen. Efter detta listar det de tyngsta användarna av minne ordnade efter sjunkande utrymmestid. Utrymmestid är produkten av mängden minne som används och hur länge det användes. Det motsvarar arean av banden i grafen, Denna del av filen talar om för oss vad vi redan vet: att den mesta utrymmestiden ägnas åt gdk_pixbuf_new. För att ta reda på vad som anropade gdk_pixbuf_new måste vi söka längre ner i textfilen:
== 4 ===========================
Context accounted for 28.8% of measured spacetime
0x6BF83A: gdk_pixbuf_new (in /usr/lib/libgdk_pixbuf-2.0.so.0.400.9)
0x3A998998: (within /usr/lib/gtk-2.0/2.4.0/loaders/libpixbufloader-png.so)
0x6C2760: (within /usr/lib/libgdk_pixbuf-2.0.so.0.400.9)
0x6C285E: gdk_pixbuf_new_from_file (in /usr/lib/libgdk_pixbuf-2.0.so.0.400.9)
Called from:
27.8% : 0x804C1A3: load_scenario (swell-foop.c:463)
0.9% : 0x3E8095E: (within /usr/lib/libgnomeui-2.so.0.792.0)
and 1 other insignificant place
Den första raden säger oss att vi är fyra nivåer ner i stacken. Under den är en lista över de funktionsanrop som leder härifrån till gdk_pixbuf_new. Slutligen finns det en lista över funktioner som är på nästa nivå neråt och anropar dessa funktioner. Det finns förstås även poster för nivå 1, 2 och 3, men detta är den första nivån som når rakt genom GDK-koden till
Nu när vi vet vilken del av vår kod som använder all utrymmestid kan vi titta på den och ta reda på varför. Det visar sig att load_scenario läser in en pixbuf från fil och sedan aldrig frigör det minnet. Eftersom vi har identifierat problemkoden så kan vi fixa den.
Att reducera användning av utrymmestid är bra, men det finns två sätt att minska det och de är inte likvärdiga. Du kan antingen minska mängden minne som allokeras, eller minska tidsperioden som det är allokerat. Tänk dig nu ett modalt system där bara två processer körs. Båda processerna använder upp nästan allt fysiskt RAM-minne, och om de någonsin överlappar kommer systemet använda växlingsutrymme och allt kommer att sakta ner. Uppenbarligen kan de samexistera utan behov att använda växlingsutrymme om vi minskar minnesanvändningen för varje process med en faktor två. Om vi istället minskar tiden minne är allokerat kan programmen samexistera, men bara så länge deras perioder av hög minnesanvändning inte överlappar. Det är därför bättre att minska mängden allokerat minne.
Dessvärre begränsas valet av optimering även av programmets behov. Storleken på pixbuf-data i
Användningen av utrymmestid för gdk_pixbuf_new är nu ett tunt band som endast tillfälligt når toppar (det är nu det sextonde bandet uppifrån och har färgen magenta). Som en bonus minskar minnesanvändningstoppen med 200 kB efter det att toppen inträffat innan annat minne allokeras. Om två processer som denna körs samtidigt är risken att topparna inträffar samtidigt, och därmed risken att växlingsutrymme behöver användas, ganska låg.
Kan vi göra bättre? En snabb undersökning av textutdata från
Command: ./swell-foop
== 0 ===========================
Heap allocation functions accounted for 87.6% of measured spacetime
Called from:
7.7% : 0x5A32A5: g_strdup (in /usr/lib/libglib-2.0.so.0.400.6)
7.6% : 0x43BC9F: (within /usr/lib/libgdk-x11-2.0.so.0.400.9)
6.9% : 0x510B3C: (within /usr/lib/libfreetype.so.6.3.7)
5.2% : 0x2A4A6B: __gconv_open (in /lib/tls/libc-2.3.3.so)
Om vi tittar närmare ser vi dock att det anropas från många, många ställen.
== 1 ===========================
Context accounted for 7.7% of measured spacetime
0x5A32A5: g_strdup (in /usr/lib/libglib-2.0.so.0.400.6)
Called from:
1.8% : 0x8BF606: gtk_icon_source_copy (in /usr/lib/libgtk-x11-2.0.so.0.400.9)
1.1% : 0x67AF6B: g_param_spec_internal (in /usr/lib/libgobject-2.0.so.0.400.6)
0.9% : 0x91FCFC: (within /usr/lib/libgtk-x11-2.0.so.0.400.9)
0.8% : 0x57EEBF: g_quark_from_string (in /usr/lib/libglib-2.0.so.0.400.6)
and 155 other insignificant places
Vi möter nu avtagande resultat för våra optimeringsförsök. Grafen tipsar om en annan möjlig infallsvinkel: både bandet ”other” och ”heap admin” är ganska stort. Detta säger oss att det finns många små allokeringar som görs från olika ställen. Att eliminera dessa blir svårt, men om de kunde grupperas skulle individuella allokeringar kunna vara större och kostnaden för ”heap admin” kunna minskas.
Det finns några saker att vara uppmärksam på: den första är att utrymmestid endast rapporteras som en procentsats, du måste jämföra den med programmets totala storlek för att avgöra om mängden minne är värd titta närmare på. Grafen är med sin vertikala kilobyteaxel bra för detta.
Den andra saken är att