2016-03-31 3 views
1

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

Программа работает при полном наклоне и выбрасывает Out of Memory Exception: верхний предел GC превышен, когда он достигает около 10000 ключей.

Я читал, что может быть, что базовый массив должен постоянно изменять размер. Но id хотел бы решить эту проблему, не увеличивая размер кучи.

Спасибо!

+0

Вы можете использовать конструктор 'InitialCapacity'' HashMap', чтобы задать желаемый размер, если вы знаете, сколько ключей у вас будет. – radoh

+0

Спасибо за ваш ответ. Я не знаю, но это определенно будет больше, чем дефолт 16. В любом месте от нескольких тысяч до нескольких миллионов. –

+0

вы можете попробовать TreeMap вместо этого, из любопытства. Это может помочь вам понять, является ли характер проблемы в реализации Карты. Ключи должны реализовывать порядок на компараторе. – user1582639

ответ

1

Вы теряете память, потому что внутренний массив удваивается каждый раз, когда выполняется определенное пороговое значение. Поэтому вам нужно убедиться, что этого не произойдет. Если вам известно количество объектов, которые необходимо сохранить на карте, просто используйте конструктор HashMap(int initialCapacity, float loadFactor) и укажите ожидаемый размер в первом параметре. Если вы не знаете количество объектов, которые по-прежнему можете попытаться установить initialCapacity так, чтобы некоторое приблизительное значение и/или играли с параметром loadFactor (значение по умолчанию 0,75) - чем больше значение, тем больше порог, в котором будет изменяться размер ,

0

Вы должны использовать профайлеры и инструменты анализатора памяти для решения проблем производительности и памяти. Один из советов, которые я хотел бы сделать, - настроить JVM с флагом JAVA_OPTS = -XX: -HeapDumpOnOutOfMemoryError Затем, когда у вас есть это исключение и сбои JVM, вы можете взять этот дамп и использовать инструмент анализа памяти MAT для анализа распределения объектов и корневые пути. Также вы бы предпочли использовать Java Mission Control JMC, распространяемый с Java, и это самописцы. Обратите внимание, что регистратор полета доступен с момента обновления Java 7. 40

+1

Зачем тратить время, если причина уже понятна автору? –

+0

Дамп кучи - прекрасный подход к анализу ошибок в памяти. OP считает, что изменение размера таблицы HashMap является виновником, но это крайне маловероятно. –

+1

Причина не ясна ни для автора, ни для нас, это его предположение, и наша цель - найти истину. – user1582639

2

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

Для простоты предположим, что вы используете 64-битную JVM с использованием сжатого OOPS (OOP = обычный указатель объекта). Это дает 12-байтовый заголовок для каждого объекта и 4-байтовый объект. Я также предполагаю, что вы используете HashMap с коэффициентом загрузки по умолчанию 0,75.

С 10 000 элементов размер стола составляет не менее 10 000/0,75 = 13,333. Однако размер таблицы всегда равен двум, поэтому, вероятно, будет 16,384. Это дает 65536 байт - 64 КБ.

Каждый элемент хранится в HashMap также требует создания внутреннего Node объекта, который имеет четыре 4-байтовых полей (хэш, ключ, значение, рядом) плюс 12 байт для заголовка объекта, что дает 28 байт в Node объекта , С 10 000 элементов, это 280 КБ.

Размер стола HashMap, а также внутренние объекты Node требуют, чтобы накладные расходы составляли 344 КБ для хранения 10 000 пар ключ-значение. Это не вызывает у вас нехватки памяти. Изменение начальной емкости HashMap приведет к уменьшению затрат на копирование при изменении размера, но объем временной дополнительной памяти, которую он занимает, пренебрежимо мал по сравнению с типичным размером кучи сотен МБ или нескольких ГБ.

Если размер вашей кучи составляет 1 ГБ, а у вас заканчивается память на 10000 записей карты, то каждая пара значений ключа принимает около 100 КБ. Вы не сможете загрузить несколько миллионов ключей, если вы не увеличите размер своей кучи, или уменьшите размер каждой пары значений ключа или какую-то комбинацию обоих.

+0

Стюарт, спасибо за подробный ответ. У вас не хватает памяти, практически синонимом сборщика мусора, работающего слишком сложно? Предположительно, он работает так усердно, потому что он отчаянно пытается вернуть память –

+0

@JohnSmith Не является синонимом, но одним из симптомов нехватки памяти является то, что сборщик мусора работает слишком часто. Предположим, у вас есть программа, которая выделяет много мелких объектов, а 90% из них - мусор. Довольно легко увидеть, что куча будет асимптотически приближаться к 100% заполнению, но для этого потребуется очень много времени. Симптомом является то, что GC будет работать все чаще и в конечном итоге потребляет больше процессора, чем потоки приложений. Примерно тогда, когда JVM выведет «превышение верхнего предела GC» OOME, которое вы видели. –