Home
Accesso / Registrazione
 di 

Programmazione orientata agli oggetti in ANSI-C. Metodi di classe per risolvere il memory leakage

Programmazione orientata agli oggetti in ANSI-C. Metodi di classe per risolvere il memory leakage

Le moderne workstation hanno parecchia memoria. Se un programma perde le tracce di un byte qua e là non fa di solito una gran differenza. Tuttavia, questi memory leaks sono di solito sintomo di errori negli algoritmi.

A volte i programmi si comportano in modo inaspettato di fronte ad un input strano oppure, ed è sicuramente un caso peggiore, il programma è stato inavvertitamente costruito per interrompere le connessioni con la memoria allocata dinamicamente. In questo capitolo discuteremo una tecnologia generale disponibile nell'ambito della programmazione object oriented che può essere usata fra le altre cose, per combattere il memory leakage.

Tutte le risorse acquisite da un programma dovrebbero essere adeguatamente riciclate. La memoria dinamica è una risorsa e i programmi dovrebbero essere controllati per evitare memory leaks. Ad esempio, consideriamo cosa succede quando facciamo un errore di sintassi mentre usiamo il calcolatore sviluppato nel capitolo 3 e 5.

$ value
(3 * 4) — —
bad factor: ’’ 0x0

L'algoritmo ricorsivo alla base del calcolatore cerca di costruire un albero delle espressioni. Se qualcosa va storto, la funzione error() usa longjmp() per eliminare qualsiasi cosa si trovi nello stack e continua l'esecuzione del programma principale. Tuttavia, lo stack contiene parti dell'albero dell'espressione che era già stato costruito. Se c'è un errore di sintassi, queste parti sono perse ed ecco che abbiamo un memory leak. Questo è un problema standard nella realizzazione di interpreti.

NeXTSTEP fornisce un'applicazione semplice MallocDebug che può essere usata per localizzare almeno alcuni dei problemi più seri. Se linkiamo value con -IMALLOCDEBUG, le versioni standard di malloc() e le funzioni relative sono rimpiazzate da un modulo che può comunicare con l'applicazione MallocDebug. Iniziamo MallocDebug dopo value, collegando i due, e premiamo un bottone Leaks quando riceviamo il primo messaggio di errore. Sfortunatamente l'output è semplicemente

No nodes

MallocDebug usa un metodo semplicissimo per verificare la presenza di leaks: ha una lista delle aree di memoria allocate e scandisce le parole nel task del client per vedere se puntano ad aree allocate. Solo le aree in cui non punta alcuna parola del task del client sono considerate essere memory leaks. Per l'input

(3 * 4) — —

sum() avrà il primo sottoalbero costruito da product() prima che factor() esegua fino alla fine della linea di comando. Tuttavia, quando error() raccoglie lo stack dopo l'esecuzione di factor() e lo ripassa a main(), l'indirizzo della radice di questo sottoalbero è ancora nella variabile locale result di sum() e, per puro caso, non viene sovrascritto in longjmp(). I nodi rimanenti sono collegati alla radice, ossia dal punto di vista di MallocDebug, tutti i nodi possono essere ancora raggiunti. Tuttavia, se digitiamo un'altra espressione il vecchio stack viene sovrascritto e MallocDebug troverà il leak:

value:
$ value
(3 * 4) — —
bad factor: ’’ 0x0
1 + 3
4
MallocDebug:
Zone: Address: Size: Function:
default 0x050ec35c 12 mkBin, new, product, sum,
factor, product, sum, stmt

Se value fosse compilato con le informazioni di debug, potremmo far partire un debugger in una seconda finestra e investigare sul leak:

$ gdb value
GDB is free software ...
(gdb) attach 746
Attaching program `value’, pid 746
0x5007be2 in read ()
(gdb) print * (struct Bin *) 0x050ec35c
Reading in symbols for mathlib.c...done.
$1 = {
type = 0x8024,
left = 0x50ec334,
right = 0x50ec348
}
(gdb) print process(0x050ec35c)
Reading in symbols for value.c...done.
$3 = void
(gdb)

Il debugger GNU può essere collegato al processo in esecuzione. Con print possiamo visualizzare il contenuto del nodo che stiamo perdendo se andiamo a copiare l'indirizzo da MallocDebug e se forniamo il tipo appropriato: mkBin() era la funzione che chiamava malloc() in origine, quindi dobbiamo riuscire ad ottenere una struct Bin. Come mostrato dall'output, print può persino chiamare un metodo come process() in value e visualizzare il risultato. L'output da process() appare nella finestra in cui value è in esecuzione:

$ value
(3 * 4) — —
bad factor: ’’ 0x0
1 + 3
4
12

Ed ecco quindi il memory leak vivo e vegeto.

 

 

Scrivi un commento all'articolo esprimendo la tua opinione sul tema, chiedendo eventuali spiegazioni e/o approfondimenti e contribuendo allo sviluppo dell'argomento proposto. Verranno accettati solo commenti a tema con l'argomento dell'articolo stesso. Commenti NON a tema dovranno essere necessariamente inseriti nel Forum creando un "nuovo argomento di discussione". Per commentare devi accedere al Blog

 

 

Login   
 Twitter Facebook LinkedIn Youtube Google RSS

Chi è online

Ultimi Commenti