5

我已经使用我的多线程程序对我的多线程程序进行了基准测试-agentlib:hprof=cpu=samples ,并且惊讶地在结果中发现以下行:

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

我从未在我的程序中明确调用 hashCode()。这可能是什么原因?如何理解这次“浪费”的来源,是否正常?

谢谢,大卫

4

3 回答 3

5

很可能您正在使用非常密集的 Map,例如 HashMap。

HashMap 用于hashCode分发对象。.equals如果您正在使用具有此数据结构的许多对象,那么您和您的.hashCode方法的正确实现非常重要。

请参阅:Effective Java Item 8: Always override hashCode when you override equals

于 2010-06-26T16:52:27.343 回答
1

您应该做的一件事是检查匹配的堆栈跟踪以查看谁在调用它;变化是它确实是HashMap。

但除此之外,我注意到 hprof 往往会大大高估对 hashCode() 的调用;我真的很想知道如何以及为什么。这是基于实际了解代码的粗略性能概况;我已经看到 50% 的 cpu 使用率(通过采样),几乎可以肯定它绝对不会花费那么长时间。hashCode() 的实现只返回一个 int 字段,并且方法是最终的(在最终对象上)。所以它基本上是某种分析器工件......只是不知道如何或为什么,或如何摆脱它。

于 2010-12-07T07:34:05.593 回答
0

你可能是对的。我实际上可以放弃对随机访问功能的使用(你是这么称呼它的吗?),而且我不在乎对象的顺序。我只需要能够添加对象然后遍历所有对象。此外,这确实是一个集合(我不需要多次使用同一个对象),但我也永远不会尝试多次添加它......我应该使用列表来代替(虽然我不在乎订购)?对于这样的集合,最有效的数据结构是什么?

HashSet 被实现为将键映射到自身的 HashMap,因此切换到 HashSet 在性能方面不会产生太大影响。

其他替代方法是 TreeSet,或者(假设您的应用程序永远不会尝试插入重复项)List 类之一。如果您的应用程序可以使用 List,那么 ArrayList 或 LinkedList 将比 HashSet 或 TreeSet 更有效。

但是,您的应用程序将 50% 的时间花在hashCode方法上是非常可疑的。除非调整哈希表的大小,否则每个 set 或 map 操作只应调用一次 hashCode 方法。所以要么有很多地图/集合调整大小,要么你正在做大量的集合add操作。(AFAIK,Object hashcode 方法很便宜,所以每次调用的成本应该不是问题。)

编辑

nextInt() 真的很贵吗?有什么选择吗?

不,它不贵。看一下代码。Random 类(和 nextInt() 方法)确实使用了 AtomicLong 来使其成为线程安全的,如果您编写了非线程安全的版本,您可能会节省几个周期。源代码在你的JDK安装目录中……看看。

于 2010-06-26T17:27:06.690 回答