hashmap поставил проблему с производительностью - PullRequest
0 голосов
/ 01 мая 2011

У меня есть хэш-карта в моем приложении.Карта находится в единственном экземпляре, и доступ к ее обновлению или чтению защищен с использованием синхронизированных методов.

Моя проблема возникает при тестировании с большим количеством (20000+) одновременных потоков.Когда потоки записывают на карту с помощью put (), я получаю исключение OutOfMemory.

Операции чтения выполняются нормально (я могу имитировать 1000000+ потоков) без каких-либо проблем.

Любые рекомендации, как я могусделать мой hashmap более производительным для записи?Это также может быть ограничением моего подхода к хранению такого большого количества данных в памяти?

Ответы [ 8 ]

4 голосов
/ 01 мая 2011

Я подозреваю, что у вас не хватает памяти PermGen из-за количества потоков.Ваше исключение OutOfMemoryError должно сообщить вам, является ли оно кучей или PermGen.

Каждый поток в Java использует около 256-512 Кбайт для своего стека, который выделяется из PermGen.Таким образом, 20 000 потоков * 256 Кбайт = 5 Гбайт, что намного превышает размер PermGen по умолчанию (обычно 64–256 Мбайт).

Количество потоков должно быть не более нескольких сотен.Взгляните на параллельный пакет Java 5/6, в частности ThreadPoolExecutor .

1 голос
/ 01 мая 2011

Вместо этого вы можете использовать ConcurrentHashMap, и он имеет больше преимуществ по сравнению с обычной картой.Я не уверен, используете ли вы Java5, поскольку он доступен только с версии 5.

Также я бы сказал, подумайте еще раз над своей логикой, действительно ли вам требуется синхронизация при операциях чтения.Если это не так, вы можете удалить это и сэкономить некоторую производительность.

Если вы действительно чувствуете проблему с нехваткой памяти, вы можете запустить jvm с большим количеством параметров памяти vm, упомянутых выше.Попробуйте.:)

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

1 голос
/ 01 мая 2011

Если вы хотите сохранить текущую реализацию, вы можете также рассмотреть возможность изменения объема памяти, выделенной для приложения, путем изменения параметров -Xms и -Xmx, передаваемых в Java. Существует много других параметров. Это может быть необходимо сделать независимо от используемой реализации.

1 голос
/ 01 мая 2011

Похоже, ваша проблема в памяти, а не в производительности.

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

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

Рассмотрим несколько уровней хэш-карт (каждый с разными ключами) для повышения производительностиэтого.

1 голос
/ 01 мая 2011

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

Что касается памяти, я подозреваю, что вы действительно много храните в JVM.Воспользуйтесь инструментом монитора, таким как visualvm, чтобы проверить это, или добавьте больше памяти для выделения JVM.Рассмотрим кеш, такой как EHCache, который автоматически переполняется на диск и внутренне использует ConcurrentHashMap и имеет все виды приятных ограничивающих опций

1 голос
/ 01 мая 2011

Если вы используете JDK1.5 +, ConcurrentHashMap - хороший выбор.Это эффективно.

См .: В чем разница между ConcurrentHashMap и Collections.synchronizedMap (Map)?

Кроме того, я думаю, что put() может привести к выделению новой памяти на карте и увеличению временипотребляет, но get() нет.Таким образом, в put().

будет заблокировано больше потоков. Также оптимизируйте метод hashCode() вашего ключевого класса.Это важно, так как вычисление хеш-кода является интенсивной операцией в вашем случае.Если ключевой объект является неизменным, вычислите хеш-код только один раз, сохраните его как член и верните его непосредственно в hashCode().

0 голосов
/ 25 августа 2011

Что касается последней части вашего вопроса:

Любые рекомендации о том, как я могу сделать мой hashmap более производительным для записи?Это также может быть ограничением моего подхода к хранению такого большого количества данных в памяти?

Я использую инструмент, чтобы взглянуть на то, что делает приложение.Это может сделать кучу и поток дампов.Он также имеет montior, который отображает процессор, загруженные классы, потоки, кучу и perm gen.Он называется Java VisualVM и является частью jdk 1.6. Exe находится в папке bin на jdk.Я собираюсь использовать его для отслеживания некоторых потоков в нашем коде.

HTH, Джеймс

0 голосов
/ 01 мая 2011

OutOfMemoryError может быть вызвано большим количеством хранимых объектов, а не большим количеством потоков, и OOME не является проблемой производительности.

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

...