2014-11-05 12 views
10

Próbuję użyć bardzo dużych kwadratowych macierzy w Javie, rzędu n = 1e6 lub więcej. Matryce nie są rzadkie, więc nie widzę zbyt wiele, aby je reprezentować jako tablice 2D, które wymagają n^2 * sizeof (int) bitów pamięci. Oczywiście, otrzymuję błędy przepełnienia sterty, nawet jeśli dodaję flagi kompilatora do użycia jako duże sterty, na co pozwala mój komputer.Maksymalizacja Java Heap Space

Jestem gotów założyć, że mam idealny komputer (nieograniczoną ilość pamięci RAM itp.) W trosce o to pytanie, chociaż w rzeczywistości jestem na 64-bitowej maszynie z 16 gigabajtami pamięci RAM. Wygląda na to, że moja maszyna jest tak ważna, ponieważ jestem ograniczony przez JVM, a nie mój rzeczywisty sprzęt (ponieważ JVM nie może mieć więcej pamięci niż moja fizyczna maszyna).

Rozumiem (i jest cytowany np. Tutaj Making a very large Java array), że tablica Java nie może być, nawet teoretycznie, większa niż MAX_INT, ponieważ jest używana do indeksowania.

Moje pytanie brzmi: czy są jakieś sposoby namówić dodatkowej pamięci na stercie JVM

Rozumiem, że jeśli istnieją, to prawdopodobnie nie będzie się do mnie ogrom więcej informacji.

Na przykład

W C, to może zadeklarować statyczne zmienne ciągłe i mają one przenoszone do sekcji danych kodu, który będzie miał dużo więcej miejsca niż w sterty i o wiele więcej niż stos (Where are static variables stored (in C/C++)?).

W Javie, wydaje się, że nawet jeśli skopiować zmienną w sekcji „Dane”, wartość będzie na głównej sterty static allocation in java - heap, stack and permanent generation co oznacza, że ​​się udało w ruchu cały jeden bajt off stercie (yay !)

moje rozwiązanie

My "rozwiązanie" nie jest to rozwiązanie. Zrobiłem prostą strukturę danych, która używa procedur RandomFileAccess io, aby zastąpić dostęp do tablicy odczytem i zapisem do zewnętrznego pliku. Nadal mamy stały dostęp do czasu, ale przeszliśmy od jednej z najszybszych operacji Java do bardzo powolnej procedury (chociaż możemy pobrać "wszystkie" wiersze z pliku naraz, co powoduje, że proces jest niesamowicie szybszy). Lepsze pomysły?

Not My Pytanie

Nie pytam jak zrobić tablicę powyżej maksymalnego rozmiaru tablicy Javy. To nie jest możliwe. Są to tablice zagnieżdżone - pojedyncza tablica o rozmiarze n jest w porządku, n powoduje problemy.

Nie pytam o to How to deal with "java.lang.OutOfMemoryError: Java heap space" error (64MB heap size). Usuwanie śmieci nie ma znaczenia - nie mogę nawet sprawić, że tablica nie będzie się martwić, kiedy zostanie usunięta.

Nie mogę również użyć iteratora (chyba), który w przeciwnym razie byłby możliwy; funkcja taka jak mnożenie macierzy musi być w stanie bezpośrednio indeksować

Uwaga: Java nie jest właściwym językiem do wykonywania operacji na bardzo dużych macierzach. Lepiej korzystam z liczydła. Ale oto jestem i to jest poza moją kontrolą.

+0

Czy można rozpowszechniać obliczenia w wielu JVM? używając czegoś podobnego do JPPF, [tutaj] (http://www.jppf.org/samples-pack/MatrixMultiplication/Readme.php) to przykład: –

+0

Czy to działa, aby po prostu przydzielić więcej pamięci RAM po uruchomieniu? – JClassic

+0

@jigar Nie wiem, zaglądam teraz! –

Odpowiedz

3

Brakuje niektórych aspektów pierwotnego pytania; na przykład nie mogę uwierzyć, że musisz używać tak dużych matryc i po prostu "zapomnieć" między biegami. Cóż, może tak, nie wiem.

W każdym razie: twoje użycie RandomAccessFile jest, imho, prawie tam; tylko, że gdybym był tobą, użyłbym FileChannel.map(). W systemach uniksowych jest to w zasadzie sposób na wywołanie mmap(2). W poniższym scenariuszu zakładam, że masz macierz FileChannel (rozumiem, co mam na myśli).

Ponieważ używasz macierzy, ponieważ wygląda na to, że wartości w dowolnych "współrzędnych" w macierzy mają tę samą długość, oznacza to, że możesz łatwo obliczyć przesunięcie w pliku, aby odczytać i/lub zapisać dane wartość do macierzy. Oczywiście nie będziecie chcieli mapować wartości na wartość, ale okno zawierające tę wartość; spraw, aby okno było wystarczająco duże, aby było użyteczne, i NIE martw się o zużycie miejsca na sterty: FileChannel.map() nie zużywa przestrzeni sterty (z wyjątkiem księgowania obiektów). W 64-bitowych JVM nie musisz się martwić; Gdybyś używał 32-bitowej maszyny JVM, musiałbyś wyliczyć wyczerpanie przestrzeni adresowej.

Pojawia się oczywiście problem wygaśnięcia: jak długo trzeba to czy inne mapowanie pozostać aktywne. Jest to całkowicie zależne od twojego programu i tego, co z nim robisz. Ale używanie drogi FileChannel i mapowanie odpowiednich stref jest drogą do zrobienia. Należy jednak pamiętać, że mapowanie więcej niż 2^31 - 1 bajtów jest niebezpieczne; ustaw na przykład okna bajtowe 2^30 (1 GiB); i przypomnij, że możesz przekonwertować ByteBuffer s na IntBuffer s.


Edycja: niektóre odpowiednie linki:

Powiązane problemy