OutOfMemoryError nello sviluppo di applicazioni: cos'è, cause e metodi di prevenzione

Autore: IT Sectr Pubblicato: 2026-03-29 Tempo di lettura: 9 min

OutOfMemoryError è un'eccezione fatale che si verifica quando la Macchina Virtuale Java (JVM) o Android Runtime (ART) non può allocare memoria per un nuovo oggetto a causa della mancanza di spazio nell'Heap. Secondo Square Engineering, il 70% degli OutOfMemoryError nelle applicazioni mobili è causato da perdite di memoria, non dal superamento effettivo del limite. Comprendere le cause di OOM è la chiave per la stabilità dell'applicazione.

Punti Chiave

  • OutOfMemoryError — un'eccezione quando l'Heap è insufficiente per creare un nuovo oggetto
  • Heap — l'area di memoria dove vivono tutti gli oggetti Java/Kotlin
  • Bitmap — il principale consumatore di Heap in Android, una tipica fonte di OOM
  • Heap Dump — un'istantanea dell'Heap per analizzare chi occupa quanta memoria
  • Trattamento di OOM richiede la correzione delle perdite e l'ottimizzazione del consumo di memoria

Cos'è OutOfMemoryError

OutOfMemoryError (OOM) è un'eccezione della famiglia VirtualMachineError in Java/Kotlin che segnala l'incapacità di allocare memoria per un nuovo oggetto. A differenza delle eccezioni verificate, OOM è un Error e non richiede gestione tramite catch — sebbene tecnicamente possa essere catturato. Dopo che si verifica un OOM, l'applicazione è solitamente in uno stato instabile e si consiglia di terminarla.

Su Android, ogni applicazione ha un limite di Heap impostato dal produttore del dispositivo. Per gli smartphone moderni con 6+ GB di RAM, il limite è di 256–512 MB, per i dispositivi economici — 128–192 MB. Quando il volume totale di tutti gli oggetti vivi supera questo limite, ART lancia OutOfMemoryError.

È importante capire: OOM non significa sempre che il dispositivo abbia esaurito la memoria fisica. Significa che l'applicazione ha esaurito il suo limite di Heap impostato dal sistema. Altre applicazioni possono avere memoria libera, ma la tua applicazione non può usarla a causa dell'isolamento dei processi in Android.

Cause Principali di OutOfMemoryError

Cinque scenari portano regolarmente a OOM nelle applicazioni mobili. Ogni scenario è associato a un tipo specifico di dati o operazione.

Bitmap Senza Ridimensionamento

Bitmap è il principale consumatore di memoria nelle applicazioni Android. Caricare un'immagine FullHD (1920 × 1080) a dimensione originale occupa 8,3 MB in formato ARGB_8888. Se ci sono 50 di queste immagini in un RecyclerView, sono 415 MB, superando l'Heap di qualsiasi dispositivo. Caricare immagini senza inSampleSize garantisce OOM sui dispositivi deboli.

Usa Glide o Coil per il ridimensionamento automatico. Queste librerie caricano le immagini con una dimensione corrispondente alla View, non alla risoluzione originale. Per l'uso diretto di BitmapFactory.Options, applica inSampleSize: calcolalo come potenza di due in modo che la dimensione finale non superi 2048 × 2048 pixel. Inoltre, usa RGB_565 invece di ARGB_8888 per le immagini senza trasparenza — questo dimezza il consumo di memoria.

kotlin
fun loadScaledBitmap(path: String, reqWidth: Int): Bitmap? {
    val opts = BitmapFactory.Options().apply {
        inJustDecodeBounds = true
    }
    BitmapFactory.decodeFile(path, opts)
    opts.inSampleSize = calculateSampleSize(opts.outWidth, reqWidth)
    opts.inJustDecodeBounds = false
    return BitmapFactory.decodeFile(path, opts)
}

Perdite di Memoria (Accumulo)

Una singola perdita di pochi KB non causerà OOM. Ma decine di perdite su ogni schermo si accumulano: ogni transizione di schermo aggiunge una perdita, il GC non può liberare oggetti e l'Heap si riempie. Un pattern tipico: l'utente apre e chiude la schermata del profilo 20 volte → l'Heap cresce di 200 MB → l'applicazione si blocca con OOM.

Installa LeakCanary nel progetto per il rilevamento automatico delle perdite. Mostrerà ogni oggetto perso con uno stack trace esatto. Dopo aver corretto tutte le perdite, il consumo di Heap diventa stabile: dopo aver chiuso uno schermo, la memoria torna al livello base.

File Grandi in Memoria

Caricare interi file in byte[] è una strada diretta verso OOM. Un file JSON di 50 MB durante l'analisi creerà una stringa della stessa dimensione più un modello DOM. File video caricati in memoria, buffer audio e grandi set di dati protobuf — tutti possono superare il limite di Heap in una singola operazione.

Elabora i dati grandi usando flussi: InputStream con buffer di 4–8 KB, parser JSON in streaming (Jackson o Gson con JsonReader), MediaCodec per video. Non chiamare mai File.readBytes() su file più grandi del 10% dell'Heap disponibile.

Creazione di Molti Oggetti in un Ciclo

La creazione intensiva di oggetti in un ciclo senza GC intermedio può portare a OOM, specialmente su dispositivi con Heap piccolo. Esempio: generare 100.000 oggetti in un for-loop che non entrano nell'Heap prima che il GC possa raccoglierli. Questo è più comune nei giochi e negli editor grafici.

Usa Object Pool per oggetti che vengono creati e distrutti in massa. Per dati numerici, usa primitivi (FloatArray invece di List<Float>). RecyclerView con ViewHolder Pool risolve questo problema per i componenti dell'interfaccia utente.

Frammentazione dell'Heap

La frammentazione è uno stato in cui c'è abbastanza memoria libera in totale, ma nessun blocco contiguo per un nuovo oggetto. ART compatta l'Heap durante il GC, ma non sempre con successo. I grandi array (Bitmap, byte[]) sono i più sensibili alla frammentazione.

ART su Android 8+ usa GC Generazionale, che riduce la frammentazione separando oggetti giovani e vecchi. Tuttavia, evita di allocare frammenti di dimensioni diverse nello stesso pool — cerca di usare buffer preallocati di dimensione fissa.

Limiti di Heap in Android

Il limite di Heap in Android non è una costante — dipende dal produttore, dal modello del dispositivo e dalla versione del sistema operativo. Google stabilisce requisiti minimi attraverso il Documento di Definizione di Compatibilità (CDD), ma i produttori impostano i valori effettivi.

Categoria DispositivoHeap TipicolargeHeap
Economico (1–2 GB RAM)128–192 MB256–384 MB
Media gamma (3–4 GB RAM)256–384 MB512 MB
Flagship (6+ GB RAM)384–512 MB768 MB–1 GB
Tablet (4+ GB RAM)256–512 MB768 MB
Wear OS32–64 MBN/D

Puoi richiedere un limite aumentato tramite android:largeHeap="true" nel manifesto. Usalo con cautela: aumentare l'Heap non risolve il problema delle perdite e può peggiorare l'esperienza utente se il sistema è costretto a uccidere altre applicazioni per liberare memoria per la tua. Per Wear OS, il limite di Heap è minimo — solo 32–64 MB, largeHeap non è disponibile qui, e il risparmio di memoria è doppiamente critico.

Diagnosi di OutOfMemoryError

La diagnosi di OOM richiede l'analisi di un Heap Dump e la comprensione di quali oggetti consumano memoria. Android Studio fornisce tutti gli strumenti necessari.

Passo 1: Cattura il momento dell'OOM. In Android Memory Profiler, fai clic su Record memory allocations ed esegui lo scenario che causa il crash. Il Profiler mostrerà un picco nelle allocazioni prima dell'OOM. Se OOM non è riproducibile, riduci l'Heap tramite android:smallHeap nella build di debug o usa DDMS con chiamata manuale di GC.

Passo 2: Prendi un Heap Dump al carico di picco (prima dell'OOM). Apri il Dump in Android Studio: la scheda Classes è ordinata per Retained Size. Gli oggetti più grandi sono Bitmap, byte[], String. Per ogni Bitmap, controlla la dimensione (larghezza × altezza × 4 byte) e il percorso di caricamento tramite Stack Trace.

Passo 3: Analizza il numero di oggetti duplicati. Se vedi 200 Fragment o Activity identici — è una perdita. Se 500 Bitmap con la stessa dimensione — è un problema di caching delle immagini. MAT (Memory Analyzer Tool) fornisce un'analisi più approfondita con un Dominator Tree che mostra quali oggetti trattengono l'80% dell'Heap.

text
// Comando Heap Dump tramite adb
adb shell am dumpheap com.example.app /data/local/tmp/dump.hprof
adb pull /data/local/tmp/dump.hprof.

Strategie di Prevenzione di OOM

Una strategia completa di prevenzione di OOM include cinque livelli di protezione: dalle decisioni architetturali al monitoraggio in produzione.

Decisioni Architetturali

ViewModel + Repository separa i dati dall'interfaccia utente e impedisce il trattenimento della View durante la rotazione dello schermo. ViewModel sopravvive all'Activity, i suoi dati non vengono persi e la View può essere ricreata senza duplicare i dati in memoria. Usa StateFlow invece di LiveData per la gestione esplicita degli stati.

Gestione di Bitmap e Immagini

Glide è una libreria obbligatoria per lavorare con le immagini. Ridimensiona, memorizza nella cache (disco + memoria) e ricicla automaticamente i Bitmap. Configura diskCacheStrategy e skipMemoryCache per elenchi grandi. Per immagini animate, usa Glide con GIF/WebP — occupano meno memoria di una sequenza di Bitmap.

Monitoraggio in Produzione

Firebase Performance Monitoring traccia il consumo di memoria in tempo reale. Imposta un avviso quando l'uso dell'Heap supera l'80% del limite — è un segnale per indagare. Crashlytics raccoglie OOM come eccezione e mostra l'ultimo stato noto dell'Heap prima del crash. Per Android 11+, usa ApplicationExitInfo per rilevare terminazioni OOM.

Test su Dispositivi Deboli

Assicurati di testare l'applicazione su dispositivi con Heap minimo (128–192 MB). Un emulatore con schermo piccolo e Heap piccolo emula un dispositivo economico. Se l'applicazione funziona su tale dispositivo, non ci saranno problemi di OOM sui flagship. Usa Firebase Test Lab con dispositivi reali di diverse fasce di prezzo.

kotlin
// Verifica Heap disponibile prima di operazione pesante
fun canAllocate(requiredBytes: Long): Boolean {
    val runtime = Runtime.getRuntime()
    val free = runtime.freeMemory()
    return free > requiredBytes * 2 // margine del 50%
}

Domande Frequenti

Si può catturare OutOfMemoryError con try-catch?

Tecnicamente sì, ma non è raccomandato. Dopo OOM, l'applicazione è in uno stato instabile: nuove allocazioni potrebbero fallire e alcuni oggetti potrebbero essere parzialmente creati. L'unica azione ragionevole in catch è la registrazione e il riavvio dell'Activity.

Perché OOM non si verifica su tutti i dispositivi?

Il limite di Heap varia tra i dispositivi. Un'operazione che richiede 300 MB fallirà su un dispositivo con limite di 192 MB ma avrà successo su un flagship con 512 MB. Testa su dispositivi con specifiche minime per rilevare scenari OOM.

Come influisce largeHeap sulle prestazioni?

largeHeap aumenta il limite ma non accelera l'applicazione. Le pause del GC diventano più lunghe poiché la raccolta di un Heap grande richiede più tempo. Il sistema potrebbe uccidere applicazioni in background per fornire memoria. Usa largeHeap solo per applicazioni che oggettivamente necessitano di molta memoria (fotocamere, editor).

In cosa differisce OOM da un kill di sistema?

OOM è un'eccezione all'interno di un'applicazione quando l'Heap è insufficiente. Un kill di sistema (Low Memory Killer) è una decisione del kernel Linux di uccidere un processo per liberare memoria per altre applicazioni. In un kill di sistema, l'applicazione non riceve un'eccezione — il processo semplicemente termina.

Quanta memoria consuma effettivamente un Bitmap?

La formula: larghezza × altezza × bytesPerPixel. ARGB_8888 = 4 B/pixel, RGB_565 = 2 B/pixel. Un Bitmap FullHD (1920 × 1080) in ARGB_8888 = 8,3 MB. Un Bitmap 4K (3840 × 2160) = 33 MB. Ridimensiona sempre le immagini alla dimensione necessaria per la visualizzazione sullo schermo.

Riepilogo

  • OutOfMemoryError — un'eccezione fatale quando il limite di Heap dell'applicazione è esaurito
  • Bitmap senza ridimensionamento — il principale colpevole di OOM nelle applicazioni mobili
  • Le perdite di memoria causano il 70% degli OOM attraverso l'accumulo di oggetti a ogni transizione
  • Limite di Heap varia da 128 MB sui dispositivi economici a 512 MB sui flagship
  • Heap Dump con analisi Retained Size — lo strumento principale per diagnosticare OOM
  • Glide o Coil sono obbligatori per lavorare con immagini di qualsiasi dimensione
  • Test su dispositivi con Heap minimo sono indispensabili per tutti i progetti

Svilupperemo un'applicazione mobile chiavi in mano

IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.

Discuti il progetto

Leggi anche