Sto scrivendo un'applicazione client-side Swing (designer grafico di font) su Java 5. Recentemente, sto correndo in java.lang.OutOfMemoryError: Java heap space
error perché non sono conservatore nell'uso della memoria. L'utente può aprire un numero illimitato di file, e il programma mantiene gli oggetti aperti in memoria. Dopo una rapida ricerca ho trovato Ergonomia nella 5.0 Java Virtual Machine e altri che dicono che sulla macchina Windows la JVM ha come default la dimensione massima di heap 64MB
.
Data questa situazione, come dovrei affrontare questo vincolo?
Potrei aumentare la dimensione massima dell'heap usando l'opzione linea di comando di java, ma questo richiederebbe di capire la RAM disponibile e scrivere qualche programma o script di lancio. Inoltre, l'aumento a qualche finito massimo non mi sbarazza in definitiva del problema.
Potrei riscrivere un po' del mio codice per persistere gli oggetti nel file system frequentemente (usare il database è la stessa cosa) per liberare la memoria. Potrebbe funzionare, ma probabilmente è anche molto lavoro.
Se poteste indicarmi i dettagli delle idee di cui sopra o alcune alternative come memoria virtuale automatica, estendere la dimensione dell'heap dinamicamente, sarebbe fantastico.
In definitiva si ha sempre un massimo finito di heap da usare, non importa su quale piattaforma si stia girando. In Windows 32 bit questo è circa 2GB
(non specificamente l'heap ma la quantità totale di memoria per processo). Succede solo che Java sceglie di rendere il default più piccolo (presumibilmente in modo che il programmatore non possa creare programmi che hanno un'allocazione di memoria incontrollata senza incorrere in questo problema e dover esaminare esattamente quello che stanno facendo).
Quindi, dato questo, ci sono diversi approcci che potreste adottare per determinare la quantità di memoria di cui avete bisogno o per ridurre la quantità di memoria che state usando. Un errore comune con i linguaggi garbage collected come Java o C# è quello di tenere in giro riferimenti a oggetti che non si usano più, o allocare molti oggetti quando invece si potrebbe riutilizzarli. Finché gli oggetti hanno un riferimento ad essi, continueranno ad usare lo spazio dell'heap poiché il garbage collector non li cancellerà.
In questo caso potete usare un profiler di memoria Java per determinare quali metodi nel vostro programma stanno allocando un gran numero di oggetti e poi determinare se c'è un modo per assicurarsi che non siano più referenziati, o per non allocarli in primo luogo. Un'opzione che ho usato in passato è "JMP" http://www.khelekore.org/jmp/.
Se stabilite che state allocando questi oggetti per un motivo e avete bisogno di tenere in giro i riferimenti (a seconda di cosa state facendo questo potrebbe essere il caso), avrete solo bisogno di aumentare la dimensione massima dell'heap quando avviate il programma. Comunque, una volta che fate il memory profiling e capite come i vostri oggetti vengono allocati, dovreste avere un'idea migliore di quanta memoria vi serve.
In generale, se non potete garantire che il vostro programma venga eseguito in una quantità finita di memoria (forse in base alla dimensione dell'input) vi imbatterete sempre in questo problema. Solo dopo aver esaurito tutto questo avrete bisogno di guardare nella cache degli oggetti su disco ecc. A questo punto dovreste avere una buona ragione per dire "Ho bisogno di Xgb di memoria" per qualcosa e non potete aggirare il problema migliorando i vostri algoritmi o gli schemi di allocazione della memoria. Generalmente questo sarà solo il caso di algoritmi che operano su grandi insiemi di dati (come un database o qualche programma di analisi scientifica) e allora tecniche come il caching e l'IO mappato in memoria diventano utili.
Esegui Java con l'opzione a riga di comando -Xmx
, che imposta la dimensione massima dell'heap.
Sì, con -Xmx
puoi configurare più memoria per la tua JVM.
Per essere sicuri di non perdere o sprecare memoria. Fai un heap dump e usa l'Eclipse Memory Analyzer per analizzare il tuo consumo di memoria.