如果我在某个对象上调用Object.hashcode()
方法,它将返回该对象的内部地址(默认实现)。该地址是逻辑地址还是物理地址?
在垃圾回收中,由于内存压缩,对象在内存中发生移位。如果我在GC之前和之后调用哈希码,它将返回相同的哈希码(返回),如果是,则为什么(由于压缩地址可能会更改)?
最佳答案
@erickson或多或少是正确的。 java.lang.Object.hashCode()
返回的哈希码在对象的生存期内不会更改。
(通常)实现此方法的方式非常聪明。当对象由垃圾回收器重定位时,其原始哈希码必须存储在某个地方,以防再次使用。实现此目的的明显方法是将32位字段添加到对象 header 以保存哈希码。但这会给每个对象增加1个字的开销,并且在最常见的情况下会浪费空间...在这种情况下,不会调用对象的hashCode
方法。
解决方案是将两个标志位添加到对象的标志字中,并按如下方式(大致)使用它们。当调用hashCode
方法时设置第一个标志。第二个标志告诉hashCode
方法是使用对象的当前地址作为哈希码,还是使用存储的值。当GC运行并重定位对象时,它将测试这些标志。如果设置了第一个标志而未设置第二个标志,则GC在对象的末尾分配一个额外的单词,并将原始对象位置存储在该单词中。然后,它设置两个标志。从那时起,hashCode
方法从对象末尾的单词获取哈希码值。
实际上,identityHashCode
实现必须以这种方式来满足general hashCode contract的以下部分:
如果/当GC将对象移至另一个地址时,仅返回对象的当前机器地址的identityHashCode()
的假设实现将违反突出显示的部分。解决此问题的唯一方法是让(假设的)JVM确保一旦调用了hashCode
,该对象就不会移动。这将导致堆碎片的严重而棘手的问题。