Избегать «ошибки нехватки памяти» в Java (затмение) при использовании большой структуры данных? - PullRequest
2 голосов
/ 17 марта 2010

ОК, поэтому я пишу программу, которая, к сожалению, должна использовать огромную структуру данных для завершения своей работы, но она завершается с ошибкой «нехватка памяти» во время инициализации. Хотя я полностью понимаю, что это значит и почему это проблема, у меня возникают проблемы с ее преодолением, поскольку моя программа должна использовать эту большую структуру, и я не знаю другого способа ее хранения.

Программа сначала индексирует большой массив текстовых файлов, которые я предоставляю. Это отлично работает.

Затем он использует этот индекс для инициализации большого двумерного массива. Этот массив будет иметь n² записей, где «n» - количество уникальных слов в корпусе текста. Для сравнительно небольшого фрагмента, который я тестирую (около 60 файлов), требуется примерно 30 000 × 30 000 записей. Это, вероятно, будет больше, как только я запусту его на своем полном корпусе.

Он последовательно терпит неудачу каждый раз, после индексации, во время инициализации структуры данных (для дальнейшей работы).

Вещи, которые я сделал, включают:

  • обновить мой код, чтобы использовать примитив int[] вместо TreeMap
  • устранение избыточных структур и т. Д. *
  • Кроме того, я запустил программу с -Xmx2g, чтобы максимально использовать выделенную память

Я вполне уверен, что это не будет простым решением кода, но, скорее всего, потребует совершенно нового подхода. Я ищу, что это за подход, есть идеи?

Спасибо, B.

Ответы [ 4 ]

2 голосов
/ 17 марта 2010

Существует несколько причин нехватки памяти.

Во-первых, самый простой случай - вам просто нужно больше кучи. Вы используете максимальную кучу 512M, когда ваша программа может корректно работать с 2G. Увеличение с -Xmx2048m в качестве опции JVM, и все в порядке. Также имейте в виду, что 64-битные виртуальные машины будут использовать в два раза больше памяти, чем 32-битные виртуальные машины, в зависимости от структуры этих данных.

Если ваша проблема не так проста, вы можете посмотреть на оптимизацию. Замена объектов примитивами и так далее. Это может быть вариантом. Я не могу сказать, основываясь на том, что ты написал.

Однако в конечном итоге вы попадаете на перекресток, где вам приходится выбирать между виртуализация и разбиение .

Виртуализация в этом контексте просто означает некоторую форму притворства, что памяти больше, чем есть. Операционные системы используют это с виртуальными адресными пространствами и используют пространство жесткого диска в качестве дополнительной памяти. Это может означать только одновременное хранение части структуры данных в памяти и сохранение оставшейся части во вторичном хранилище (например, в файле или базе данных).

Разделение разделяет ваши данные на несколько серверов (реальных или виртуальных). Например, если вы отслеживаете биржевые торги на NASDAQ, вы можете поместить биржевые коды, начинающиеся с «A» на server1, «B» на server2 и т. Д. Вам нужно найти разумный подход, чтобы разделить ваши данные так, чтобы уменьшить или устраните необходимость в кросс-коммуникациях, потому что именно кросс-коммуникация ограничивает вашу масштабируемость.

В таком простом случае, если вы сохраняете 30K слов и 30K x 30K словосочетаний, вы можете разделить его на четыре сервера:

  • А-М х А-М
  • A-M x N-Z
  • N-Z x A-M
  • N-Z x N-Z

Это всего лишь одна идея. Опять же, это трудно сделать, не зная специфики.

2 голосов
/ 17 марта 2010

Похоже (если сделать некоторые предположения о том, для чего вы используете свой массив), большинство записей будет равно 0. Если это так, вы можете рассмотреть возможность использования разреженной матрицы представления.

Если у вас действительно есть такого количества записей (ваш текущий массив где-то превышает 3 гигабайта уже , даже при условии отсутствия издержек), то вам придется использовать какое-то -дисковое хранилище или система отложенной загрузки / выгрузки.

1 голос
/ 17 марта 2010

Это распространенная проблема, связанная с большими наборами данных. Вы можете оптимизировать столько, сколько хотите, но памяти никогда не будет достаточно (вероятно), и как только набор данных станет немного больше, вы все равно будете курить. Наиболее масштабируемое решение - просто хранить меньше памяти, работать с частями и сохранять структуру на диске (база данных / файл).

0 голосов
/ 17 марта 2010

Если вам не нужны полные 32 бита (размер целого числа) для каждого значения в вашем двумерном массиве, возможно, меньший тип, такой как байт, сработает? Также вам следует выделить как можно больше кучи - 2 ГБ все еще относительно малы для современной системы. Оперативная память дешева, особенно если вы ожидаете много обработки в памяти.

...