JVM Tunning класса Java

Мой класс 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?

3 ответа

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

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

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

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

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

Теперь займемся математикой.

300.000.000 Double s, каждые 24 байта, используют 7 200 000 000 байтов памяти, что составляет 7,2 ГБ.
Если вы храните 300.000.000 doubles, занимая 4 байта каждый, вам нужно только 1 200 000 000 байтов, что составляет 1,2 ГБ.
Поздравляю, вы сохранили около 83% памяти, которую ранее использовали для хранения своих номеров!

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

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

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

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

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

Другие вопросы по тегам