Minnesläckage

Minnesläckage är en datavetenskaplig term för en typ av resursläcka som uppstår när ett datorprogram hanterar minnesallokeringar på ett felaktigt sätt[1] så att minne som inte längre behövs aldrig blir frigjort. Inom objektorienterad programmering kan minnesläckage inträffa när ett objekt lagras i minnet men inte kan kommas åt av körande kod.[2] Ett minnesläckage har symptom som liknar ett antal andra problem (se nedan) och kan vanligtvis endast undersökas av en programmerare med tillgång till programmets källkod.

Konsekvenser

Ett minnesläckage kan sänka en dators prestanda genom att reducera mängden tillgängligt minne. Till slut, i värsta fall, kan för mycket av det tillgängliga minnet allokeras och alla eller delar av systemet eller enheten sluta fungera på rätt sätt, applikationen slutar fungera eller systemets prestanda sjunker kraftigt på grund av den skapade bristen av arbetsminne.

Minnesläckage behöver inte vara allvarligt eller ens märkbart med normala medel. I moderna operativsystem frigörs det minne som en applikation använder när applikationen stängs. Detta betyder att en minnesläcka i ett program som endast körs en kort stund inte märks och därför sällan är allvarligt.

Mycket mer allvarligare läckor inkluderar:

  • när programmet körs en längre tid och konsumerar ytterligare minne med tiden, som bakgrundsprocesser på servrar, men speciellt i inbyggda enheter som kan köras i flera år
  • när nytt minne allokeras frekvent för engångsuppgifter, som när bildrutor i ett datorspel eller video renderas
  • när programmet kan begära minne — exempelvis delat minne — som inte frigörs, även om programmet stängs
  • där minnet är mycket begränsat, som i ett inbyggt system eller en bärbar enhet
  • där läckan uppstå inom operativsystemet eller minneshanterare
  • när en drivrutin i ett system orsakar läckan

Ett exempel på minnesläckage

Följande exempel, som är skrivet i pseudokod, är avsedd att visa hur en minnesläcka kan uppstå och dess konsekvenser utan krav för någon programmeringskunskap. Detta program är en del av en enkel programvara byggd för att styra en hiss. Denna del av programmet körs när någon i hissen trycker på en våningsknapp.

När en knapp trycks ned:
  Hämta lite minne som kommer att användas för att komma ihåg våningsnumret
  Stoppa in våningsnumret i minnet
  Är vi redan på begärd våning?
    I så fall behöver ingenting göras: färdig
    Annars:
      Vänta tills hissen står still
      Gå till begärd våning
      Frigör minnet som användes för att kommer ihåg våningsnumret

Minnesläckan skulle uppstå om den begärda våningsnumret är samma som våning som hissen är på; villkoret för att frigöra minnet skulle då hoppas över. Varje gång detta händer kommer mer minne läckas.

Tillstånd som detta skulle vanligtvis inte ha någon omedelbara effekter. Folk trycker oftast inte på knappen för den våningen de redan är på och hur som helst kanske hissen har tillräckligt mycket minne kvar så att detta kan ändra hundra eller tusentals gånger. Hissen kommer till slut att få slut på minne. Detta kan ta månader eller år, så det kanske inte upptäcks även om koden testas.

Konsekvenserna skulle bli obehagliga; hissen skulle åtminstone sluta reagera på begäran att flytta till en annan våning. Om andra delar i programmet behöver minne (en del tilldelas till exempel till att öppna och stänga dörren) kanske någon blir instängd där eftersom programvaran inte kan öppna dörren.

Minnesläckage kvarstår tills systemet återställs. Till exempel om hissens ström stängs av skulle programmet sluta köras. När strömmen slås på igen skulle programmet behöva starta om och allt minne skulle finnas tillgängligt igen, men minnesläckan skulle även startas om tillsammans med programmet och småningom sakta påverka hur systemet körs.

Läckan i exemplet ovan kan korrigeras genom att frigöra utanför villkoret:

 När en knapp trycks ned:
   Hämta lite minne som kommer att användas för att komma ihåg våningsnumret
   Stoppa in våningsnumret i minnet
   Är vi redan på begärd våning?
     Annars:
       Vänta tills hissen står still
       Gå till begärd våning
   Frigör minnet som användes för att kommer ihåg våningsnumret

Programmeringsproblem

Minnesläckage är ett vanligt problem inom programmering, speciellt när man använder programspråk som inte har en inbyggd skräpsamlare, som C och C++. Vanligtvis uppstår en minnesläcka på grund av att dynamiskt allokerat minne har blivit onåbart. Förekomsten av minnesläckande buggar has lett till att felsökningsverktyg har utvecklats för att upptäcka onåbart minne. Funktionaliteter i "konservativa" skräpsamlare kan läggas till i alla programmeringsspråk som saknar det som en inbyggd funktionalitet, och programbibliotek för att göra detta finns tillgängliga för program i C och C++. En konservativ samlare hittar och återkallar det mesta, men inte allt, onåbart minne.

Även om minneshanteraren kan återställa onåbart minne kan den inte frigöra minne som fortfarande är onåbart och är därefter fortfarande användbart. Moderna minneshanterare kan därefter tillhandahålla tekniker till programmerare för att betydelsemässigt märka minne med varierande nivåer av användbarhet, vilket motsvarar olika nivåer av nåbarhet. Minneshanteraren frigör inte ett objekt som är starkt nåbar. Ett objekt är starkt nåbart om det är nåbart antingen direkt av en stark referens eller indirekt av en kedja av starka referenser. (En stark referens är en referens som, till skillnad från en svag referens, förhindrar ett objekt från att hamna i en skräpsamlare.) För att förhindra detta är utvecklaren ansvarig för att rensa upp referenser efter att de har använts, vanligtvis genom att sätta referensen som NULL så fort den inte längre behövs och att avregistrera alla händelselyssnare som upprätthåller starka referenser till objektet.

I allmänhet är automatiska minneshanterare mer robusta och lämpliga för utvecklare då de inte behöver implementera frigörande rutiner eller oroa sig om vilken ordning upprensningen utförs eller vara bekymrad om ett objekt fortfarande är refererat eller inte. Det är enklare för en programmerare att veta när en referens inte längre behövs än att veta när ett objekt inte längre behövs refereras. Automatisk minneshanterare kan däremot införa en prestandaöversikt och eliminerar inte alla programmeringsfel som orsakar minnesläckage.

Påverkan

Om ett program har en minnesläcka och dess minnesanvändning sjunker stadigt kommer vanligtvis inte några omedelbara symptom synas. Varje fysiskt system har en ändlig mängd minne och om minnesläckan inte hejdas (till exempel genom att starta om det läckande programmet) kommer den förr eller senare börja orsaka problem.

De flesta moderna operativsystemen har både ett huvudminnen som finns i RAM och ett sekundärminne som en hårddisk. Minnesallokering är dynamisk – varje process får så mycket minne som den begär. Aktiva pages överförs till huvudminnet för snabb åtkomst; inaktiva pages förflyttas till sekundärminnet för att skapa utrymme efter behov. När en process börjar konsumera mycket minne tar den upp mer och mer huvudminne och trycker ut andra program som vanligtvis till följd saktar ned systemets prestanda. Även om läckande program stängs ned kan det ta en stund för andra program att flyttas tillbaka till huvudminnet och för att prestandan ska bli normal igen.

När allt minne på ett system töms (om det finns ett virtuellt minne eller bara primärminne, som exempelvis i ett inbyggt system) kommer alla försök att allokera mer minne att misslyckas. Detta orsakar vanligtvis programmet som försöker allokera minnet att stänga ned sig själv eller att generera ett segmenteringsfel. En del program är designade att återhämtas från denna situation (möjligtvis genom att förlita sig på reserverat minne). Det första programmet som får slut på minne behöver vanligtvis inte vara samma program som har minnesläckan.

En del multikörande operativsystems har speciella mekanismer för att hantera fall där minnet tar slut, som att stänga processer slumpartat (som kan påverka "oskyldiga" processer) eller stänga de största processerna i minnet (vilket förmodligen är det som orsakar problemet). En del operativsystem har en minnesgräns för varje process för att förhindra något program från att ta åt sig allt systemminne. Nackdelen med detta är att operativsystemet ibland måste konfigureras för att låta program som är i större behov av minne, exempelvis de som hanterar grafik, video eller vetenskapliga beräkningar, fungera som de ska.

Om minnesläckaget är inuti operativsystemkärnan kommer själva operativsystemet förmodligen att krascha. Datorer utan någon sofistikerad minneshantering, som inbäddade system kan också krascha på grund av en ihärdig minnesläcka.

Ett enkelt exempel i C

Följande funktion i C läcker avsiktligt minne genom att förlora pekaren till det allokerade minnet. Man kan säga att läckan uppstår så fort pekaren "a" hamnar utanför definitionsområdet, d.v.s. när function_which_allocates() returnerar utan att frigöra "a".

#include <stdlib.h>

void function_which_allocates(void) {
    /* allokera en array med 45 tal av typen float */
    float *a = malloc(sizeof(float) * 45);

    /* mer kod som använder "a" */

    /* returnerar till main och glömmer bort att frigöra minnet vi allokerade */
}

int main(void) {
    function_which_allocates();

    /* pekaren "a" finns inte längre och kan därefter inte frigöras,
     men minnet är fortfarande allokerat: en läcka har uppstått. */
}

Se även

Referenser

Den här artikeln är helt eller delvis baserad på material från engelskspråkiga Wikipedia.

Noter

Externa länkar