Профилирование Java: java.lang.Object.hashCode занимает половину процессорного времени, но никогда не вызывается явно - PullRequest
5 голосов
/ 26 июня 2010

Я тестировал мою многопоточную программу, используя -agentlib:hprof=cpu=samples и был удивлен, обнаружив в результатах следующую строку:

rank   self  accum   count trace method
   1 52.88% 52.88%    8486 300050 java.lang.Object.hashCode

Я никогда явно не вызываю hashCode () в моей программе. В чем может быть причина этого? Как понять источник для этого времени "отходов" и нормально ли это или нет?

Спасибо, David

Ответы [ 3 ]

5 голосов
/ 26 июня 2010

Скорее всего, вы очень интенсивно используете карту, такую ​​как HashMap.

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

См .: Эффективный элемент Java 8: Всегда переопределяйте hashCode, когда выпереопределение равно

1 голос
/ 07 декабря 2010

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

Но кроме того, я заметил, что hprof имеет тенденцию к чрезмерной переоценке вызовов hashCode (); и я действительно хотел бы знать, как и почему. Это основано на фактическом знании приблизительного профиля производительности кода; и я видел 50% -ное использование процессора (путем выборки), когда почти наверняка это займет совсем немного времени. Реализация hashCode () просто возвращает поле int, а метод final (для конечного объекта). Так что это в основном какой-то артефакт профилировщика ... просто не знаю, как и почему, или как от него избавиться.

0 голосов
/ 26 июня 2010

Вы, наверное, правы. На самом деле я могу отказаться от использования возможностей произвольного доступа (так вы это называете?), И меня не волнует порядок объектов. Мне просто нужно иметь возможность добавлять объекты, а затем перебирать их все. Кроме того, это действительно набор (мне не нужен один и тот же объект более одного раза), но я также никогда не буду пытаться добавить его более одного раза ... Должен ли я использовать список вместо этого (хотя мне все равно порядок)? Какая структура данных наиболее эффективна для такого набора?

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

Другими альтернативами являются TreeSet или (при условии, что ваше приложение никогда не попытается вставить дубликат) один из классов List. Если ваше приложение таково, что List будет работать, то ArrayList или LinkedList будут более эффективными, чем HashSet или TreeSet.

Однако в вашем приложении есть что-то очень подозрительное, тратя 50% своего времени на hashCode методы. Если размеры хеш-таблиц не изменились, метод hashCode должен вызываться только один раз для каждой операции набора или сопоставления. Таким образом, либо происходит большое изменение размеров карты / набора, либо вы выполняете огромное количество операций набора add. (AFAIK, метод Object hashcode является дешевым, поэтому стоимость каждого вызова не должна быть проблемой.)

EDIT

Действительно ли nextInt () дорого? Есть альтернативы?

Нет, это не дорого. Посмотрите на код. Класс Random (и метод nextInt ()) действительно используют AtomicLong, чтобы сделать его поточно-ориентированным, и вы можете сэкономить несколько циклов, если вы закодировали не поточно-ориентированную версию. Исходный код находится в вашем каталоге установки JDK ... посмотрите.

...