2014-11-05 19 views
10

Sto cercando di utilizzare matrici quadrate molto grandi in Java, nell'ordine di n = 1e6 o più. Le matrici non sono sparse, quindi non vedo molto per rappresentarle come un array 2D, che richiede n^2 * sizeof (int) bit di memoria. Ovviamente, sto ricevendo errori di overflow di heap, anche quando si aggiungono i flag del compilatore per utilizzare un heap di grandi dimensioni come consentirà la mia macchina.Ottimizzazione dello spazio di heap Java

Sono disposto ad assumere che abbia il computer perfetto (RAM illimitata, ecc.) Per il gusto della domanda, anche se in realtà sono su una macchina a 64 bit con 16 GB di RAM. Sembra che la mia macchina sia così rilevante, dal momento che sono limitato dalla JVM e non dal mio hardware (in quanto la JVM non può avere la memoria più della mia macchina fisica).

Capisco (ed è citato, ad esempio, qui Making a very large Java array) che un array Java non può essere, anche teoricamente, più grande di MAX_INT come quello utilizzato per l'indicizzazione.

La mia domanda è: ci sono modi di convincere memoria aggiuntiva fuori dal mucchio JVM

Capisco che, se ci sono, probabilmente non mi ottenere una grandezza più informazioni.

Per esempio

In C, posso dichiarare variabili costanti statiche e li hanno spostato nella sezione dati del codice che avrà molto più spazio di cumulo e molto più della pila (Where are static variables stored (in C/C++)?).

In Java, sembra che anche se copio la variabile in una sezione "Dati", il valore sta andando sul mucchio principale static allocation in java - heap, stack and permanent generation il che significa che sono riuscito a passare un intero byte di fuori del mucchio (yay !)

mia soluzione

mia "soluzione" in realtà non è una soluzione. Ho creato una semplice struttura dati che utilizza le procedure RandomFileAccess per sostituire gli accessi agli array con la lettura e la scrittura su un file esterno. È sempre l'accesso al tempo costante, ma siamo passati da una delle operazioni più veloci di Java a una procedura molto lenta (anche se siamo in grado di inserire le righe "cache" dal file tutto in una volta, il che rende il processo estremamente più veloce). Migliori idee?

Not My Domanda

Non sto chiedendo come fare una matrice sopra dimensione massima gamma di Java. Non è possibile. Questi sono matrici annidate - una matrice di dimensioni n singole va bene, n di esse causa problemi.

Non sto chiedendo questo How to deal with "java.lang.OutOfMemoryError: Java heap space" error (64MB heap size). La raccolta dei dati inutili non è pertinente - non posso nemmeno fare in modo che l'array non si preoccupi di quando viene eliminato.

Non riesco a utilizzare un iteratore (credo), che altrimenti sarebbe una possibilità; una funzione come la moltiplicazione della matrice deve essere in grado di indicizzare direttamente

Nota: Java non è la lingua giusta per eseguire operazioni su matrici di grandi dimensioni. Farei meglio ad usare un abaco. Ma io sono qui e questo è fuori dal mio controllo.

+0

puoi distribuire il calcolo in più JVM? usando qualcosa come JPPF, [qui] (http://www.jppf.org/samples-pack/MatrixMultiplication/Readme.php) è un esempio –

+0

Funzionerebbe per allocare più ram quando si esegue? – JClassic

+0

@jigar Non lo so, guardandolo adesso! –

risposta

3

Ci sono alcuni aspetti mancanti alla tua domanda originale; per esempio, non posso credere che tu debba usare matrici così grandi e semplicemente "dimenticarle" tra le esecuzioni. Beh, forse lo sai, non lo so.

In ogni caso: l'utilizzo di RandomAccessFile è, imho, quasi lì; solo che se fossi in te, userei FileChannel.map(). Sui sistemi Unix, è fondamentalmente un modo per chiamare mmap(2). Nello scenario seguente, presumo che tu abbia un FileChannel nella tua matrice (suppongo capisci cosa intendo).

Poiché si utilizzano le matrici, poiché sembra che i valori di una qualsiasi "coordinata" nella matrice abbiano tutti la stessa lunghezza, significa che è possibile calcolare facilmente l'offset nel file per leggere e/o scrivere un dato valore nella matrice. Ovviamente, non vorrai mappare lo del valore, ma una finestra contenente tale valore; rendere la finestra abbastanza grande da essere utile, e NON preoccuparti del consumo di spazio heap: FileChannel.map() non consuma spazio heap (salva per la contabilità degli oggetti). Su JVM a 64 bit, non devi preoccuparti; Se avessi usato una JVM a 32 bit, avresti dovuto tenere conto dell'esaurimento dello spazio degli indirizzi.

Esiste, ovviamente, il problema della scadenza: per quanto tempo è necessario che questa o quella mappatura restino attive. Questo dipende interamente dal tuo programma e da cosa lo fai. Ma usare il FileChannel e mappare le zone rilevanti è la strada da percorrere. Tuttavia, è necessario ricordare che non è sicuro mappare più di 2^31 - 1 byte; accontentarsi di finestre di byte 2^30 (1 GiB), ad esempio; e ricorda che puoi convertire ByteBuffer s in IntBuffer s.


Edit: alcuni link rilevanti:

Problemi correlati