Мой класс 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?
Ваш набор данных смехотворно большой, чтобы обрабатывать его в памяти, это не окончательное решение, а просто оптимизация.
Вы используете бокс-примитивы, что очень болезненно, на что можно смотреть. В соответствии с этим вопросом целое число в штучной упаковке может быть на 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 *.
Ваш набор данных достаточно велик, чтобы его одновременное хранение в памяти не происходило.
Рассмотрите возможность хранения данных в базе данных и загрузки частичных наборов данных для выполнения манипуляций.
Изменение: Мое предположение состояло в том, что вы собирались сделать более одного прохода по данным. Если все, что вы делаете, это загрузить его и выполнить одно действие для каждого элемента, то предложение Lex Webb (комментарий ниже) является лучшим решением, чем база данных. Если вы выполняете более одного действия для каждого элемента, то база данных представляется лучшим решением. База данных не обязательно должна быть базой данных SQL, если ваши данные ориентированы на запись, база данных NoSQL может быть лучше подходит.
Вы используете неправильные структуры данных для данных этого тома. Java добавляет значительные накладные расходы в памяти и времени для каждого объекта, который он создает, и на уровне 300 миллионов объектов вы просматриваете множество накладных расходов. Вы должны оставить эти данные в файле и использовать методы произвольного доступа для его устранения - взгляните на файлы с отображением памяти, используя nio.
Map.Entry<Integer, Double>
поэтому для 300 миллионов записей требуется по меньшей мере 25 ГБ (вероятно, значительно больше, поскольку у вас также будет наборMap.Entry<Integer, HashMap<...>>
и другие вещи в памяти)