Memory leak

Da Wikipedia, l'enciclopedia libera.

In informatica, un memory leak ("perdita o fuoriuscita di memoria") è un particolare tipo di consumo non voluto di memoria dovuto alla mancata deallocazione dalla stessa, di variabili/dati non più utilizzati da parte dei processi.

Come spiegato sotto, un memory leak ha sintomi simili a quelli di altri problemi, e generalmente può essere diagnosticato solo da un programmatore che ha accesso al codice sorgente. Molte persone tendono ad indicare qualsiasi aumento involontario del consumo di memoria, come un memory leak, anche se non è proprio la stessa cosa.

Conseguenze di un memory leak[modifica | modifica wikitesto]

Un memory leak può peggiorare le performance del computer riducendo la quantità di memoria disponibile. L'allocazione di memoria viene di solito gestita dal sistema operativo, cosicché il risultato di un memory leak è un aumento dell'occupazione di memoria dell'intero sistema, e non solo del programma che lo ha creato. Nel caso peggiore, troppa memoria viene sprecata dai leak ed il sistema può smettere di funzionare correttamente.

I leak possono non essere gravi o rintracciabili con mezzi normali. Nei moderni sistemi operativi, la memoria utilizzata da un processo viene automaticamente rilasciata al termine del processo, il che significa che un memory leak causato da un programma che resta in esecuzione per poco tempo raramente è grave.

I casi in cui un leak diventa serio comprendono:

  • quando il programma è lasciato in esecuzione, e consuma memoria continuamente (come lavori eseguiti in background, su server o su sistemi embedded lasciati in esecuzione per vari anni);
  • quando il programma è capace di richiedere memoria (come la memoria condivisa) non rilasciata anche quando il programma termina;
  • quando il leak viene creato all'interno del sistema operativo;
  • quando la memoria è molto limitata.

Un semplice esempio[modifica | modifica wikitesto]

Questo esempio vuole dimostrare come un leak può nascere, ed i suoi effetti, senza dover conoscere le basi della programmazione. Questo è solo un esempio fittizio.

Il programma in questione fa parte di un software molto semplice dedicato al controllo di un ascensore. Questa porzione di algoritmo viene eseguita ogni volta che qualcuno all'interno preme un bottone.

Quando il bottone viene premuto:

  • recupera un po' di memoria per ricordare il piano richiesto
  • metti il numero richiesto in memoria
  • siamo già al piano giusto?
  • se sì, non dobbiamo fare niente: finito
  • altrimenti, aspetta finché l'ascensore è disponibile
  • vai al piano richiesto
  • rilascia la memoria usata per ricordare il numero del piano

Questo programma potrebbe sembrare corretto, ma contiene un leak. Consideriamo il caso in cui l'ascensore si trova al piano 3 e premiamo il bottone 3. Otteniamo un po' di memoria che non restituiremo mai. Ogni volta che succede perdiamo un po' di memoria.

Questo problema non avrà un effetto immediato. Le persone non premono il bottone di un piano su cui stanno, ed in ogni caso ci può essere abbastanza memoria da gestire questa situazione centinaia o migliaia di volte. Ma alla fine la memoria finirà. Potrebbe richiedere mesi o anni, o potrebbe non essere mai scoperto.

Le conseguenze potrebbero essere sgradevoli; alla fine l'ascensore smetterebbe di funzionare. Se il programma avesse bisogno di memoria per aprire le porte, qualcuno potrebbe restare intrappolato all'interno, visto che non abbiamo risorse per aprirle.

Bisogna notare che il memory leak aumenta finché il programma è in esecuzione. Ad esempio, se un calo di elettricità blocca l'ascensore, al ritorno dell'alimentazione la memoria sarà completamente disponibile ed il lento processo di perdita di memoria deve ricominciare da zero.

Problemi di programmazione[modifica | modifica wikitesto]

I memory leak sono errori comuni nella programmazione, specialmente se si utilizzano linguaggi di programmazione che non hanno un garbage collection automatico, ad esempio il C o il C++. Tipicamente, questo errore si presenta quando un'area di memoria allocata dinamicamente è diventata irraggiungibile. L'esistenza di questi problemi ha portato allo sviluppo di molti programmi di debug che permettono di scoprirli in anticipo. Purify, Valgrind, Insure++ e memwatch sono solo alcuni dei più popolari per C e C++.

I linguaggi di programmazione che forniscono una gestione automatica della memoria, come Java, C# o Lisp, non sono immuni dai memory leak. Nonostante il memory manager possa recuperare la memoria irraggiungibile (e quindi inutile) non può liberare la memoria che ancora può essere raggiunta (e quindi è potenzialmente utile). I più moderni collector permettono al programmatore di marcare la memoria con vari livelli di utilità, corrispondenti a vari livelli di raggiungibilità. Il manager non libera memoria se è fortemente raggiungibile. Un oggetto viene detto fortemente raggiungibile se è linkato direttamente da una strong reference o indirettamente da una catena di strong reference (una strong reference è una reference che, a differenza di una weak, evita che un oggetto venga cancellato dal garbage collector). Per evitare questo tipo di memory leak, lo sviluppatore è responsabile della pulizia della memoria dopo l'utilizzo, solitamente settando la reference a NULL quando non è più necessaria.

In linea di massima, la gestione automatica è molto più robusta e conveniente per gli sviluppatori visto che non devono creare un sistema alternativo. È più semplice per un programmatore sapere quando una reference non è più necessaria piuttosto che sapere quando un oggetto non è più referenziato. Bisogna però sottolineare che il sistema automatico, oltre a non eliminare tutti gli errori, obbliga il sistema ad un ulteriore lavoro.

Effetti di un memory leak[modifica | modifica wikitesto]

Se un programma ha un memory leak ed il suo uso di memoria viene continuamente aumentato, non ci saranno sintomi immediati. Quasi tutti i sistemi hanno una certa quantità di memoria disponibile che può essere assegnata ai processi. Alla fine la memoria RAM disponibile può esaurirsi. Questo potrebbe portare a due effetti:

  • Nei sistemi in cui tutta la memoria è RAM c'è un immediato fallimento
  • Molti sistemi operativi moderni usano il disco fisso per fornire memoria virtuale. Quando la RAM finisce viene aumentato l'uso del disco fisso. Anche il disco fisso può finire lo spazio, ma prima di arrivare a quel punto il programma sarà talmente lento che verrà considerato fallito in anticipo.

Se un sistema va in crash per le continue richieste di memoria, probabilmente siamo davanti ad un bug o perlomeno ad un design scadente. Quello che normalmente succede è che il programma alla fine chiederà memoria che gli verrà negata, o perché è terminata o per aver raggiunto il proprio limite. Quello che succede a questo punto dipende dal programma:

  • termina, probabilmente con un messaggio d'errore
  • tenta di autoripararsi. Di solito questo tentativo fallisce perché necessita di memoria. A volte le applicazioni partono riservandosi un po' di memoria proprio per evitare questi problemi.
  • continua l'esecuzione come se niente fosse. Questo porterà ad un access violation rovinando informazioni di questa o (in sistemi primitivi) altre applicazioni.

È un memory leak?[modifica | modifica wikitesto]

L'aumento continuo di memoria utilizzata non indica necessariamente un leak. Alcuni programmi accumulano informazioni in memoria (cache). Se la cache cresce tanto da creare problemi, può indicare errori di design, ma non memory leak visto che quella memoria è in realtà raggiungibile. In altri casi il programma potrebbe aver bisogno di una grande quantità di memoria perché il programmatore l'ha ritenuta sufficiente per un particolare task (un programma grafico potrebbe caricarsi in memoria un intero file di immagine).

Per dirlo con altre parole, un memory leak nasce da un particolare tipo di errore di programmazione e, senza avere accesso al codice, si può solo dire che "potrebbe" essere un leak. È meglio usare un termine come "aumento continuo di uso di memoria" se non si è sicuri della causa. Tuttavia esistono dei tool come valgrind che permettono di analizzare il programma mentre è in esecuzione tramite l'utilizzo di speciali librerie modificate al posto di quelle standard. Simili tool consentono l'individuazione di memory leak senza analizzare staticamente il codice sorgente.

Il termine memory leak è forte ed i non-programmatori potrebbero usarlo per indicare errori non relativi alla memoria come i buffer overrun.

Semplice esempio di memoria irraggiungibile in C[modifica | modifica wikitesto]

Presentiamo una funzione C che, volontariamente, causa dei leak. Poiché il programma cicla in eterno chiamando la funzione errata, alla fine creerà il problema.

#include <stdio.h>
#include <stdlib.h>
int f(void)
{
    char* s;
    s = malloc(50); /* ottieni memoria */
    if (s==NULL) return 1; /* non è disponibile */
    else
    {   /* è disponibile */
        return 0;  /* memory leak – vedi la nota sotto */ 
    }
    /* 
     * La memoria era disponibile e puntata da s, ma non 
     * salvata. Dopo questo ritorno di funzione il puntatore
     * viene distrutto e la memoria diventa irraggiungibile
     *
     * Per correggere il codice bisogna aggiungere l'istruzione
     * "free(s) all'else prima di "return 0"
     */
}

int main(void)
{
    /* questo è un loop infinito che richiama il metodo di sopra */
    while (1) f(); /* Questa funzione fallirà prima o poi */
    return 0;
}

Voci correlate[modifica | modifica wikitesto]

Collegamenti esterni[modifica | modifica wikitesto]

Informatica Portale Informatica: accedi alle voci di Wikipedia che trattano di Informatica