JVM Tunning класса Java

1

Мой класс java читается в 60-мегабайтном файле и создает HashMap HashMap с более чем 300 миллионами записей.

HashMap<Integer, HashMap<Integer, Double>> pairWise =
                             new HashMap<Integer, HashMap<Integer, Double>>();

Я уже настроил аргумент VM:

-Xms512M -Xmx2048M

Но система все еще идет:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.HashMap.createEntry(HashMap.java:869)
    at java.util.HashMap.addEntry(HashMap.java:856)
    at java.util.HashMap.put(HashMap.java:484)
    at com.Kaggle.baseline.BaselineNew.createSimMap(BaselineNew.java:70)
    at com.Kaggle.baseline.BaselineNew.<init>(BaselineNew.java:25)
    at com.Kaggle.baseline.BaselineNew.main(BaselineNew.java:315)

Какая большая куча потребуется для запуска без сбоев с OOME?

  • 1
    Попытка построить матрицу сходства 300 x 300 миллионов - довольно плохая идея, даже если у вас 2 ГБ кучи.
  • 0
    Используя упрощенный тест, я измеряю что-то вроде 90 байтов для Map.Entry<Integer, Double> поэтому для 300 миллионов записей требуется по меньшей мере 25 ГБ (вероятно, значительно больше, поскольку у вас также будет набор Map.Entry<Integer, HashMap<...>> и другие вещи в памяти)
Теги:
jvm
heap-memory
jvm-arguments

3 ответа

5

Ваш набор данных смехотворно большой, чтобы обрабатывать его в памяти, это не окончательное решение, а просто оптимизация.

Вы используете бокс-примитивы, что очень болезненно, на что можно смотреть. В соответствии с этим вопросом целое число в штучной упаковке может быть на 20 байтов больше, чем целое число unboxed. Это не то, что я называю эффективностью памяти.

Вы можете оптимизировать это со специализированными коллекциями, которые не вставляют примитивные значения. Один из них - это Trove. Вы можете использовать TIntDoubleMap вместо HashMap<Integer, Double> и TIntObjectHashMap вместо HashMap<Integer, …>.

Поэтому ваш тип будет выглядеть так:

TIntObjectHashMap<TIntDoubleHashMap> pairWise =
                         new TIntObjectHashMap<TIntDoubleHashMap>();

Теперь сделайте математику.

300.000.000 Double, каждый 24 байта, использует 7.200.000.000 байт памяти, что составляет 7,2 ГБ.
Если вы храните 300 000 000 double с, занимая по 4 байта, вам нужно всего 1.200.000.000 байт, что составляет 1,2 ГБ.
Congrats, вы сохранили около 83% памяти, которую вы ранее использовали для хранения ваших номеров!

Обратите внимание, что этот расчет груб, зависит от платформы и реализации и не учитывает память, используемую для карт HashMap/T *.

  • 0
    Спасибо, это кажется хорошим решением. Я скачал банку. Но, кажется, нельзя импортировать как другие библиотеки JAR? Ты знаешь как это сделать?
  • 0
    Я не уверен, что понимаю ваше намерение, и при этом я не знаю, в какой среде вы разрабатываете. Я предполагаю, что Eclipse или IntelliJ, и в обоих случаях это должно работать прямо. Я не могу помочь вам без дополнительной информации.
Показать ещё 6 комментариев
3

Ваш набор данных достаточно велик, чтобы его одновременное хранение в памяти не происходило.

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

Изменение: Мое предположение состояло в том, что вы собирались сделать более одного прохода по данным. Если все, что вы делаете, это загрузить его и выполнить одно действие для каждого элемента, то предложение Lex Webb (комментарий ниже) является лучшим решением, чем база данных. Если вы выполняете более одного действия для каждого элемента, то база данных представляется лучшим решением. База данных не обязательно должна быть базой данных SQL, если ваши данные ориентированы на запись, база данных NoSQL может быть лучше подходит.

  • 2
    Или просто не читайте весь файл сразу, если возможно, читайте и обрабатывайте информацию по крупицам.
1

Вы используете неправильные структуры данных для данных этого тома. Java добавляет значительные накладные расходы в памяти и времени для каждого объекта, который он создает, и на уровне 300 миллионов объектов вы просматриваете множество накладных расходов. Вы должны оставить эти данные в файле и использовать методы произвольного доступа для его устранения - взгляните на файлы с отображением памяти, используя nio.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню