Chi fa il nostro mestiere prima o poi deve affrontare dei problemi di memoria… che la si perda a causa di stress e del passare degli anni, o si scriva programmi che si affidano ad allocazione/deallocazione automatica, prima o poi tutti abbiamo problemi con questo prezioso strumento.
Il caso peggiore: memory leak in applicazione web Java
Tempo fa lavorando ad un grosso progetto web sviluppato in Java (JSF2) ci ritrovammo a metterci le mani nei capelli a causa di qualche memory leaks che rendevano per così dire “poco scalabile” la nostra applicazione. Allora usammo l’Eclipse Memory Analyzer MAT, strumento molto potente e ben fatto che permette di analizzare lo heap di qualunque applicazione Java.
Su un’applicazione web certi problemi possono essere devastanti, mentre in programmi che girano localmente su macchine provviste di parecchia RAM spesso nemmeno ci si rende conto che il nostro programma sta lentamente mangiando tutta la memoria senza rilasciarla, finché va in crash. Se però questa cosa succede di rado, e in quelle poche occasioni stavamo facendo operazioni parecchio onerose, spesso nemmeno ci facciamo caso e/o facciamo finta di niente.
Memory leak?
Se non siete uno degli ultimi due personaggi della vignetta dovreste sapere a grandi linee di che si tratta, ma nel dubbio cerco di spiegarlo in poche parole: un programmatore ha sbagliato qualcosa e tra le righe di codice c’è qualche operazione che occupa memoria senza rilasciarla al termine.
Se non si programma in C raramente ci si deve preoccupare di allocare e deallocare la memoria manualmente, perché quasi tutti i linguaggi gestiscono la memoria autonomamente, allocandola ad ogni nostra dichiarazione di variabile, e facendola liberare da un garbage collector. Il GC è un processo demone che scansiona l’area di memoria dove risiedono gli oggetti e le variabili creati dal nostro programma ed elimina quelli rimasti per così dire “isolati”, ovvero che non sono più referenziati da nessuno o che sono collegati solo a oggetti non referenziati da parti “vive” dell’applicazione. In presenza di GC i memory leak sono rari perché il GC a differenza nostra non si dimentica di liberare la memoria, ma a volte proprio non ce la fa a causa di strutture mal progettate che generano riferimenti “eterni” a variabili che credevamo temporanee, e in questi casi sono dolori.
Analisi della memoria su Xcode
Sviluppando in nativo su iOS non so quanto spesso capiti di dover profilare l’applicazione alla ricerca di problemi di memoria, ma parlando di Titanium io personalmente ho dovuto preoccuparmene in più di un’occasione. Il Mac è un prodotto del demonio, però Xcode fornisce alcuni validi strumenti che in questi frangenti tornano molto utili. Vediamo come profilare un’applicazione alla ricerca di problemi di memoria e di prestazioni.
Aprendo un progetto Xcode ci si trova di fronte la finestra delle impostazioni generali, e qui dobbiamo definire le impostazioni di deploy. Generalmente la versione di iOS e il tipo di dispositivo.
Scegliamo la destinazione del nostro test, tra eventuali dispositivi collegati al Mac e simulatori del tipo selezionato al passo precedente. Fatto questo dobbiamo ricompilare il progetto. Considerato che stiamo per fare una profilazione, tanto vale fare il “Build for > profiling”, e al termine avviamo la profilazione con “Profile”.
Selezioniamo il tipo di template che più si adatta alle nostre esigenze o creiamo un template contenente tutte le metriche che ci interessano.
Nella schermata che si apre, quando siamo pronti, premiamo il tasto di registrazione e l’applicazione inizia a girare mandando dati agli strumenti di diagnostica scelti.
In cima all’elenco possiamo leggere istante per istante i dati generali i utilizzo della memoria, e subito sotto quali sono i tipi di oggetti che contribuiscono in maggior misura a saturare la nostra cara RAM. Il diagramma parla più di tutti, se questo inizia lentamente ad assomigliare ad una sega inclinata verso l’alto sono cazz… problemi.
Se certe parti del flusso del programma sono sospette e volete vedere in dettaglio come cambia l’utilizzo della memoria facendo una determinata operazione non serve segnarsi i numeri sul foglio ma possiamo usare l’utilissimo pulsante “Mark generation”. Questo serve a scattare un’istantanea di un certo punto, istantanee che possono poi essere confrontate per vedere come cambia l’utilizzo della memoria tra queste diverse “generazioni” (e quali oggetti rimangono in memoria).
Nel mio caso la memoria rimane stabile e decresce alla chiusura di alcune finestre parecchio pesanti. Se in certi punti pensate ci siano dei memory leak ma i “buchi sul tubo” sono troppo piccoli da rilevare potete prendere un trapano e allargare il buco… basta aggiungere delle immagini o in generale blob pesanti in variabili sospette per vedere meglio la RAM che se ne va.
Sviluppo per iOS su Titanium
Se stiamo sviluppando con Titanium probabilmente Xcode lo conosciamo molto poco, eppure nella vostra cartella del progetto (sotto build/iphone
) ci dovrebbe essere un file .xcodeproj
. Apritelo e vi ritroverete con il progetto Xcode che potete maneggiare e lanciare a piacimento
Senza scomodare Xcode
Certi strumenti sono molto potenti e possono aiutarvi molto, ma se siete dei romantici e preferite migliorare le prestazioni del vostro programma basandovi solo sull’intuito potete comunque usare la finestra di Monitoraggio delle attività di OSX. Ogni programma lanciato nel simulatore iPad/iPhone è un processo a se stante, e potete quindi tenere sempre sott’occhio la memoria che questo utilizza.
Intuito, Xcode, oscilloscopio, qualunque mezzo decidiate di usare l’importante è che ogni tanto verifichiate la stabilità e la non eccessiva onerosità dei vostri programmi. Alcuni utenti non sono molto comprensivi – giustamente – quando l’applicazione si rallenta in modo esagerato con il passare del tempo o peggio scompare dalla loro vista all’improvviso.