Det är ibland lätt att glömma det jag skulle vilja påstå är tickande bomber när det gäller både testning och utveckling – minnesläckor!
Testarna kan ibland svära sig fria från minnesläckor då det inte är deras avdelning, det skall utvecklarna ta med white-box verktyg osv. Utvecklarna kan i sin tur påstå att det inte läcker i de få testfall som de provar. I många fall så gör ingen någonting åt detta.
Risk för risk så att säga.
Det finns många sätt att testa minnesallokeringar på. Jag tänkte ge ett exempel hur det kan bli om det finns ett intresse från både utveckling och testsidan. Vi hade en serverprogramvara där komplexiteten var riktig hög. Att monitora varje testfall manuellt ansågs kosta alldeles för mycket.
Istället tog utvecklingssidan fram en s.k. instrumenterad server, det var samma server fast med ett bibliotek från m-patrol som hade koll på minnesallokeringen. Så när servern terminerade så kom det ut en prydlig fil med alla allokeringar som inte hade återlämnats. Efter lite instrumentering av koden så tog vi bort de allokeringar som bara hade instansieras en gång och endast en gång bort, då alla allokeringar inte var läckor.
Därav, kom det en fil så fanns det en anledning att kolla om detta scenario läckte.
Genom vår automattestframework kunde vi köra igenom alla tester och få ut vilka testfall som indikerade läckor. På detta sätt tog vi många läckor, men långt ifrån alla, då täckningen av automattesterna inte var i tillräcklig nivå. Den instrumerade servern användes flitigt för att hitta läckor även när vi testade manuellt.
Däremot så hade den instrumerade servern ett problem när det gällde testtyper. I funktionstest lämpade den sig bra, men däremot så var det problem med prestandan när vi körde prestandatester. Prestandan var inte detsamma och servern blev mycket långsammare. Dock när vi väl hittade en misstänkt allokering och hade debug symbolerna till hand så kunde vi se exakt i koden vart allokeringarna gjordes.
I det fallet fick gamla fina mätmetoder såsom task managern eller processmonitorn användas istället,om man kör på windows. På unix har vi den gamla vännen “ps” att ta till. Nu är det inte endast processens private bytes vi behöver ha koll på när vi mäter läckor. “Handles” av olika sort behöver man också att ha kontroll över och så trådhanteringen.
Microsoft har ett gammalt fint verktyg “umhd” som kan vara bra att slänga ett getöga på. Jag skrev själv ett användargränsnitt till detta verktyg en gång i tiden. Umhd är dock ett litet trubbigt verktyg, men om ni behöver ett verktyg till windows och har tiden att sätta in Er på djupet så kan det vara värt investeringen.
Så vill man inte bygga in det i sin programvara, vilket kan vara ett problem då man inte testar exakt den version som kommer till kund så finns det varianter där man kan ha icke processpåverkan. De är inte lika effektiva och enkla men kan vara en lösning.
Nyckeln är att vara med från början och få vara med och påverka kraven, inte bara så att kraven blir testbara utan på att också få in krav som handlar om hur man kan testa produkten bättre.
Så till sist, glöm inte av de tickande bomber som finns där ute i produkterna. Framöver kommer jag publicera en artikel även om läckor i webapplikationer, något som verkar vara en uppåtgående trend och därmed ett problem.
Länkar:
1. M-patrol http://mpatrol.sourceforge.net/
Intressant läsning…vilket programspråk var applikationen skriven i?
CPU-utnyttjandet kan vara en annan intressant parameter att hålla ett öga på…exempelvis oändliga loopar är en klassiker som kan ställa till det 🙂
Programmet var skrivet i C++. C/C++ har större risk när det gäller läckage än t.ex. JAVA som har som sin famösa garbage collector.
CPU-utnyttjande är en av alla saker som man bör hålla koll på men som jag inte anser är en läcka. Det som jag skrev var också att man bör kolla av trådhanteringen (trådläckage är ett vanligt fel) och handtag (handles) för process och fil.
Jag kommer ihåg en gång då jag undrade varför programmet kraschade efter ett par timmars hård men jämn körning. Efter ett tag satte vi på alla tänkbara processmonitorer och kom fram till att processen käkade filehandles stokastiskt. När vi väl hade hittat det så var fixen en smal sak, jag tror det tog utvecklaren ungefär två minuter att hitta och åtgärda problemet.
CPU och andra typer av monitoring återkommer vi till lite senare i en annan artikel, om nu inte någon hinner före och skriver om det.
Programmet var skrivet i C++
Misstänkte det 🙂
CPU-utnyttjande är en av alla saker som man bör hålla koll på men som jag inte anser är en läcka.
Korrekt, jag tänkte på intressanta parametrar generellt och jag ser fram emot kommande artiklar i frågan…
Roligt och lärorik.
Min erfarenhet är att man med ganska små medel kan hitta rätt många problemområden. Med hjälp av kommandon och funktioner som redan är inbyggda i plattformen kan man ofta komma åt de mesta och “största” felen. Som vanligt är det väll en avvägning mellan ekonomi, tid, risk osv…
Det jag ser dock är att denna typ av tester inte alltid är “standard” hos testavdelningarna jag besökt. och att när man inför ett enkelt testfall av läck/prestanda typ så hittar man ofta intressanta saker att nysta i. Så fram för mer test av den här typen, det mår vi all gott av.
Tack för kommentaren Martin!
Jag håller med dig i allt du säger. En fördel som jag kan se det när man bygger in det i programmet själv är att du kan få sådana här tester utförda med minimal arbetsinsats när det är väl på plats. Nackdelen är att det krävs kompetens och vilja från alla inblandade samt att man faktiskt ändrar testobjektet. Det är en risk man får bedöma om det är värt.
Tycker man inte det är värt risken så tycker jag att man gott kan använde de verktyg som finns i de flesta plattformar för att mäta. Det viktiga är att man verkligen inte glömmer detta område, då just detta är en av de stora dyra bomberna när de väl är ute.
Att en funktion inte fungerar kan vissa kunder ta. Däremot att programmen kraschar i tid och otid, är oftast en väldig dyrt problem!
Jag inser när jag läser denna artikel att jag i alldelas för stor utsträckning förlitar mig på prestandatester och uthållighetstester när det gäller att upptäcka minnesläckor och för högt cpu utnyttjande. Funktionstester på servrar med lämplig instrumentering för att hitta minnesläckor är något jag måste införa som en rutin, inte bara när vi faktiskt har ett konstaterat minnes problem.
Jonas: Prestandatestning och stabilitetstestning är oftast då man “tänker” på denna typ av testning. Problemet är ofta att man inte testar speciellt många scenarior i dessa typer då det tar tid. Därför om man vill verkligen vara duktig på detta område och minska risken så måste man tänka på det här i alla testnivåer.
I de projekt som man får vara med och ta fram kraven till projekten har störst möjlighet att lyckas att få till mjukvaran med bäst kvalitet. Att komma in när allt är “färdigt” har alltid de största riskerna.
Mycket intressant ämne detta!
Det bör finnas några fler artiklar att skriva inom detta område.
Har test avdelningen få resurser kan det var svårt att prioritera upp stabilitetstestning. En möjlig utväg i sådan miljö kan vara att exekvera den på samma testfall som man använder för att testa prestanda, eftersom de ibland kan likna varandra till hur de exekveras.
Skillnaden blir då endast att när man testar stabilitet använder andra verktyg, tex. Performance Monitor (private bytes, handles, threads) osv..
Har man större budget och ska stabilitetstesta kritiska server system, telefon-OS eller device driver testning eller liknande bör dock stabilitetstester vara viktigare att utföra än tex många låg-prioriterade funktionella tester.
Man bör ju tillägga här att man inte (alltid) behöver exekvera programmet eller systemet för att mäta stabilitet utan en del kan testas med hjälp av kod-analysator vertyg, tex de som är inbyggt i C++ Visual Studio.
Här finns en tutorial för ett sådant verktyg den intresserade: http://msdn.microsoft.com/en-us/library/ms182028.aspx (man bör dock ha white-box testningskunskap för att dra nytta av denna tutorial.)
Common coding errors reported by the tool include buffer overrun, un-initialized memory, null pointer dereference, memory and resource leaks.