Corso interattivo di programmazione per iPhone: IV Lezione. Gestione della memoria.

Oggi trattiamo l’argomento relativo alla gestione della memoria

corsoiphoneitalia1

internettranslatorbanner1

Nell’ ultima lezione abbiamo visto a grandi linee la logica della programmazione ad oggetti. Abbiamo visto come creare un oggetto, definire delle variabili dell’ oggetto e definire dei metodi.

Le variabili sono dei “contenitori” dove vengono memorizzate delle informazioni. Oggi vedremo abbastanza in dettaglio come richiedere questo spazio ma soprattutto la teoria del retain/release/dealloc : come liberare lo spazio.

Allocazione della memoria

Vediamo il caso piu` semplice di “richiesta” di memoria, quello che riguarda le variabili di tipo int, char, double, float etc..

Quando abbiamo bisogno di memorizzare un intero utilizziamo un int o un long int.

picture-16In questo modo dichiariamo una variabile di tipo “int” di nome “n” nella quale memorizziamo il numero 5. Se avete letto la guida riguardo le varibili, che vi avevo consigliato sapete che un int occupa 4 byte, cioe` 32bit (1 byte = 8bit).

Quindi quando dichiariamo un int noi andiamo ad occupare 4byte di memoria. Ma quand’e` che questa memoria viene liberata ?

 

picture-24

 

In questa funzione laMiaFunzione, una funzione esempio completamente inutile, vengono dichiarate 3 variabili di tipo int: n, a e b. Quello che avviene dal punto di vista della memoria e` questo:

1) Viene chiamata la funzione laMiaFunzione

2) Viene occupato lo spazio dalle variabili n,a,b (12 byte di memoria)

3) Viene fatto un calcolo

4) La funzione termina, liberando i 12 byte di memoria

 

Quando trattero` i controlli di flusso (istruzioni if/ else if/ else) parlero` di scope di variabili e quindi questo “liberare” la memoria sara` piu` chiaro.

Quindi in una situazione semplice come “laMiaFunzione” quando la funzione finisce la memoria viene liberata. Ma e` tutto cosi` semplice ? Ovviamente no!

In Objective-C noi utilizziamo soprattutto oggetti. Noi accediamo agli oggetti tramite delle variabili dette puntatori.

picture-35

La variabile “laMiaStringa” e` un puntatore. All’ interno di questa variabile c’e` scritto l’ indirizzo di memoria per accedere all’ oggetto NSString che contiene la stringa “Hello World”.

puntatori

 

Questo grafico dovrebbe farvi capire la differenza tra puntatore ed oggetto.

Considerando il puntatore pluto, non e` che in pluto e` contenuto l’ oggetto NSString con la stringa @”Pluto”. Nella variabile pluto e` memorizzato l’ indirizzo di memoria dov’e` allocato l’ oggetto NSString. Il puntatore punta ad una zona di memoria. Quindi il puntatore pluto ci permette di accedere alla zona di memoria dov’e` contenuta l’ informazione che ci interessa.

Capire questo e` fondamentale perche` in questo modo si capisce che se non si deallocano gli oggetti, la memoria rimane occupata senza riuscire piu` a recuperarla: memory leak  (http://it.wikipedia.org/wiki/Memory_leak)

Vediamo un po` in che cosa consiste un memory leak

allocazionememoria4

 

 

La funzione laMiaFunzione viene chiamata e non inizialmente non ci sono puntatori dichiarati e neanche oggetti allocati.

 

allocazionememoria3

Scrivendo NSString *pippo; dichiariamo un puntatore che ci permette di puntare ad un oggetto NSString (Il puntatore pippo verra` perso alla chiusura della funzione).

 

 

allocazionememoria5

Dichiaro un altro puntatore: pluto.

allocazionememoria6Ora allochiamo un oggetto NSString che contiene la stringa “Pippo” e lo associamo al puntatore NSString *pippo.

La memoria per il nuovo oggetto viene allocata e il puntatore pippo contiene l’ indirizzo di memoria per accedere all’ oggetto NSString.

 

allocazionememoria7Alloco un altro oggetto NSString.

[[NSString alloc] initWithString:@”Pluto”]  equivale a scrivere  pluto = @”Pluto”;

Nell’ ultima riga e` esplicita l’ allocazione di memoria e l’ inizializzazione dell’ oggetto con la stringa @”Pluto”.

 

Ora se chiudessimo la stringa avremmo un bel memory leak. La memoria persa coincide con quella che non potremo piu` utilizzare.

 

allocazionememoria8Questo avviene perche` quando la funzione termina, i puntatori vengono persi e quindi non e` piu` possibile accedere agli oggetti perche` non c’e` piu` nessuna variabile (nessun puntatore) che contenga i vari indirizzi di memoria per accedere agli oggetti.

 

Metodi RETAIN, RELEASE e RetainCount.

 

Nel caso precedente se vogliamo deallocare (liberare) la memoria occupata dall’ oggetto prima che la funzione ritorni (si concluda), dobbiamo dire all’ oggetto di liberare la memoria. Questo si fa con il comando release. In realta` fra poco vedremo che non e` detto che la memoria venga subito liberata.

allocazionememoria9In questo caso scrivendo [pippo release]; deallocheremo l’ oggetto liberando la memoria.

Il motivo per cui prima dicevo che con il metodo release l’ oggetto venga deallocato e` perche` il metodo release non dealloca subito l’ oggetto. Il metodo release decrementa il retainCount.

Un oggetto puo` esser utilizzato da piu` metodi, da piu` processi (NSThread). Per capire cosa significa “oggetto utilizzato da piu` processi” proviamo a pensare ad un sacchetto che viene riempito e svuotato da piu` persone contemporaneamente. Ogni persona e` un processo che utilizza l’ oggetto.

Se inizialmente c’e` solo una persona che e` interessata all’ utilizzo dell’ oggetto il retainCount di questo oggetto e` a 1.

Se arriva un’altra persona e vuole anche lei utilizzare lo stesso sacchetto, questa aumenta il retainCount dell’ oggetto chiamando il metodo retain

                                                                               [oggetto retain];

In questo modo il retainCount dell’ oggetto passa da 1 a 2, dicendo che ci sono due persone che stanno utilizzando l’ oggetto.

Arriva una terza persona e porta il retainCount da 2 a 3 tramite il comando [oggetto retain];

La prima persona non e` piu` interessata ad utilizzare il sacchetto e se ne va, prima di andarsene abbassa il retainCount tramite il comando  

                                                                             [oggetto release];

In questo modo il retainCount passa da 3 a 2.

Quando il retainCount divenza zero, viene automaticamente chiamato il metodo dealloc dell’oggetto, liberando subito la memoria.

Un esempio

 

picture-54picture-64

Prendiamo il codice della lezione precedente: il nostro progetto Automobili.

Implementiamo sotto il nostro oggetto Car, il metodo dealloc. Questo metodo, come dicevo prima, viene chiamato quando il retainCount va a zero.

picture-110

Quando verra` chiamato il metodo dealloc, comparira` una scritta “DEALLOCO macchina”

picture-92picture-101Come si nota dal log, quando il retainCount diventa zero (inutilizzo dell’ oggetto), questo viene deallocato.

 

Piccola bugia a fin di bene

Prima vi ho mostrato come fare il retain ed il release di stringhe. Ragionare con le stringhe e` , inizialmente, il modo migliore per prendere confidenza con i concetti di memoria. In realta` quando si fanno allocazioni di stringhe del tipo

                                           NSString *pippo = @”Pippo”;

la stringa @”Pippo” viene messa nella memoria statica da parte del compilatore, cioe` non c’e` bisogno di deallocarla (o meglio.. non e` proprio possibile dellocarla).

Provate a vedere il retainCount della stringa pippo

picture-45

picture-36

Se proviamo a forzare il dealloc vediamo che riceviamo un errore

 

picture-65

 

picture-55

Questo perche` la stringa @”Pippo” e` dichiarata staticamente.

Un esempio invece nel quale viene utilizzata la memoria dinamica (e quindi e` necessario utilizzare retain/release) e` questo

 

picture-72

 

picture-83

 

Questi concetti e` normale non siano immediati. L’ esperienza vi permettera` di capire pian piano come viene gestita la memoria e soprattutto una approfondita lettura del pdf da me gia` da tempo consigliato.

 

 


 


NovitàAcquista il nuovo iPhone 16 su Amazon
News