Чем больше я использую Java HashMap, тем больше падает производительность - даже при стабильном размере - PullRequest
0 голосов
/ 19 сентября 2011

Я хочу просканировать огромный корпус текста и посчитать частоты слов (частоты n-грамм на самом деле для тех, кто знаком с NLP / IR).Я использую Java HashMap для этого.Итак, что происходит, я обрабатываю текст построчно.Для каждой строки я извлекаю слова, а для каждого слова я обновляю соответствующую частоту в хэш-карте.

Проблема в том, что этот процесс становится все медленнее и медленнее.Например, он начинает с обработки около 100 тыс. Строк в секунду - и производительность начинает падать сразу же.После примерно 28 миллионов строк производительность упала до 16 000 строк в секунду - и, конечно, продолжает падать.

Первое, что пришло в голову, было то, что это было вызвано слишком большим количеством записей в хэш-карте, что вызывало каждыйположить и каждый раз будет медленнее.Поэтому я пытался в любое время сохранять только самые частые записи (например, 100 КБ) в хэш-карте.Это было сделано с помощью второй карты, которая отображала частоты в слова (как здесь: Автоматически сортируется по карте значений в Java )

В целом это работало намного быстрее.(хотя он начинался со скорости 56 тыс. строк в секунду, к тому времени, когда он достиг 28 млн. строк, производительность снизилась до 36,5 тыс. строк в секунду).Тем не менее, он также продолжал падать, гораздо медленнее, но факт остается фактом, что он продолжал падать.

Есть ли у вас какое-либо возможное объяснение того, почему это происходит, когда размер хэш-карты остается прежним?Как вы думаете, это как-то связано с сборщиком мусора?Это означает, что факт, что я продолжаю помещать и удалять объекты в / из хэш-карт, фрагментирует память или что-то еще?Или это может быть проблема с функцией хеширования?Поскольку я использую строки, функция хеширования является функцией хеширования Java по умолчанию для строк.

Вот часть моего кода, которая выполняет вышеупомянутую задачу:

http://pastebin.com/P8S6Sj86

ПРИМЕЧАНИЕ: я новичок в Java, поэтому любые уточнения в ваших ответах приветствуются

Ответы [ 2 ]

3 голосов
/ 19 сентября 2011

Я рекомендую использовать Java VisualVM для профилирования. Это происходит с Java - перейдите в командную строку и введите jvisualvm для его запуска. Это позволяет легко определить, является ли проблема с памятью вашей проблемой или сотни тысяч раз создаются определенные типы объектов.

Если вы разбите свой код на несколько методов, вы также сможете определить, какие методы выполняются слишком долго.

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

Например:

float avg = new Float(sumItems) / new Float (freqMap.size());

должно быть просто

float avg = (float)sumItems / freqMap.size();

Еще один фрагмент вашего кода, который также может быть проблематичным:

System.out.println(numItems + " items counted");

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

1 голос
/ 19 сентября 2011

Предложение:

Попробуйте реализовать собственный метод hashCode для объекта, который вы храните в своей hashmap.Вот несколько ссылок:

Оптимизация производительности Java HashMap / альтернатива

http://www.ibm.com/developerworks/java/library/j-jtp05273/index.html

http://www.javamex.com/tutorials/collections/hash_function_guidelines.shtml

Плохая идея использовать строковый ключ в HashMap?

...