1.8 Hashtable
Hashtable是一种使用非常频繁的基础集合类型。需要理解影响Hashtable的效率有两个因素:
- 一是散列码(GetHashCode方法)
- 二 是等值比较(Equals方法)。
Hashtable首先使用键的散列码将对象分布到不同的存储桶中,随后在该特定的存储桶中使用键的Equals方法进 行查找。
良好的散列码是第一位的因素,最理想的情况是每个不同的键都有不同的散列码。Equals方法也很重要,因为散列只需要做一次,而存储桶中查找键可能需要做多次。
从实际经验看,使用Hashtable时,Equals方法的消耗一般会占到一半以上。System.Object类提供了默认的GetHashCode实现,使用对象在内存中的地址作为散列码。
我们遇到过一个用Hashtable来缓存对 象的例子,每次根据传递的OQL表达式构造出一个ExpressionList对象,再调用QueryCompiler的方法编译得到 CompiledQuery对象。
以ExpressionList对象和CompiledQuery对象作为键值对存储到Hashtable中。ExpressionList对象没有重载GetHashCode实现,其超类ArrayList也没有,这样最后用的就是System.Object类 的GetHashCode实现。由于ExpressionList对象会每次构造,因此它的HashCode每次都不同,所以这个 CompiledQueryCache根本就没有起到预想的作用。
这个小小的疏漏带来了重大的性能问题,由于解析OQL表达式频繁发生,导致 CompiledQueryCache不断增长,造成服务器内存泄漏!解决这个问题的最简单方法就是提供一个常量实现,例如让散列码为常量0。
虽然这会导 致所有对象汇聚到同一个存储桶中,效率不高,但至少可以解决掉内存泄漏问题。当然,最终还是会实现一个高效的GetHashCode方法的。