Максимизация пространства кучи Java

Я пытаюсь использовать очень большие квадратные матрицы в Java, порядка n = 1e6 или более. Матрицы не разрежены, поэтому я не вижу много способов представить их как 2D-массив, для которого требуется n ^ 2 * sizeof (int) бит памяти. Очевидно, что я получаю ошибки переполнения кучи даже при добавлении флагов компилятора для использования как большой кучи, как позволяет моя машина.

Я согласен предположить, что у меня есть идеальный компьютер (неограниченная оперативная память и т.д.) ради вопроса, хотя на самом деле я на 64-битной машине с 16 гигабайтами оперативной памяти. Кажется, что моя машина только настолько уместна, так как я ограничен JVM не моим фактическим оборудованием (в том, что JVM не может иметь больше памяти, чем моя физическая машина).

Я понимаю (и цитируется, например, здесь Создание очень большого массива Java), что массив Java не может быть, даже теоретически, больше MAX_INT, поскольку который используется для индексирования.

Мой вопрос: есть ли способы уговорить дополнительную память из кучи JVM

Я понимаю, что, если они есть, они, вероятно, не получат мне больше информации.

Пример

В C я могу объявить статические постоянные переменные и переместить их в раздел данных кода, который будет иметь гораздо больше места, чем куча, и намного больше, чем стек (Где хранятся статические переменные (в C/С++)?).

В Java, кажется, что даже если я скопирую переменную в раздел "данные", значение переходит в основную кучу статическое распределение в java - куча, стек и постоянное поколение, что означает, что мне удалось переместить один общий байт из кучи (yay!)

Мое решение

Мое "решение" на самом деле не является решением. Я создал простую структуру данных, которая использует процедуры RandomFileAccess io для замены доступа к массиву с помощью чтения и записи во внешний файл. Это по-прежнему постоянный доступ к времени, но мы перешли от одной из самых быстрых операций Java к очень медленной процедуре (хотя мы можем вытаскивать "кеш-строки" из файла все сразу, что делает процесс чрезвычайно быстрым). Лучшие идеи?

Не мой вопрос

Я не спрашиваю, как сделать массив выше максимального размера массива java. Это невозможно. Это вложенные массивы - один массив размером n отлично, n из них вызывает проблемы.

Я не спрашиваю об этом Как бороться с "java.lang.OutOfMemoryError: пространство кучи Java" ошибка (размер кучи размером 64 МБ). Сбор мусора не имеет значения - я даже не могу заставить массив не беспокоить о том, когда он будет удален.

Я также не могу использовать итератор (я думаю), что в противном случае было бы возможным; функция, подобная матричному умножению, должна иметь возможность напрямую индексировать

Примечание. Java не является подходящим языком для операций на очень больших матрицах. Мне было бы лучше использовать счеты. Но вот я и это вне моего контроля.

Ответ 1

Есть некоторые недостающие аспекты вашего исходного вопроса; например, я не могу поверить, что вам нужно использовать такие большие матрицы и просто "забыть их" между прогонами. Ну, может, и так, я не знаю.

В любом случае: ваше использование RandomAccessFile есть, imho, почти там; только если бы я был вами, я использовал бы FileChannel.map(). В системах Unix это в основном способ вызова mmap(2). В приведенном ниже сценарии я предполагаю, что у вас есть FileChannel к вашей матрице (я полагаю, вы понимаете, что я имею в виду).

Поскольку вы используете матрицы, поскольку, похоже, что значения в любых заданных "координатах" в матрице имеют одинаковую длину, это означает, что вы можете легко вычислить смещение в файле для чтения и/или записи заданного значения в матрицу. Конечно, вам не нужно отображать это значение, но окно, содержащее это значение; сделайте окно достаточно большим, чтобы быть полезным, и НЕ беспокойтесь о потреблении пространства кучи: FileChannel.map() не потребляет кучу пространства (кроме ведения бухгалтерии объекта). На 64-битных JVM вам не нужно беспокоиться; если бы вы использовали 32-битную JVM, вам пришлось бы учитывать исчерпание адресного пространства.

Существует, конечно, проблема истечения срока действия: как долго вам нужно, чтобы такое или что отображение оставалось активным. Это полностью зависит от вашей программы и того, что вы с ней делаете. Но использование FileChannel и отображение соответствующих зон - путь. Однако вам следует напомнить, что небезопасно отображать более 2 ^ 31 - 1 байт; например, для двухбайтовых окон размером 2 ^ 30 (1 гигабайт); и напомните, что вы можете преобразовать ByteBuffer в IntBuffer s.


Изменить: некоторые релевантные ссылки: