integer默认_深度解析默认 hashCode() 的工作机制

(给ImportNew加星标,提高Java技能)

编译:ImportNew/唐尤华

srvaroa.github.io/jvm/java/openjdk/biased-locking/2017/01/30/hashCode.html

本文由浅入深,由hashCode()表面入手,深入JVM源代码从对象布局、偏向锁角度分析默认hashCode()对程序性能产生的巨大影响。

非常感谢Gil Tene和Duarte Nunes对本文审查、建议和编辑,并且提出了非常宝贵的意见。文中如有错误都是我的问题。

细节之谜

上周,我在工作中对一个类进行了一次不起眼的修改,把toString()的实现做了改进,这样日志看起来更容易理解。结果让我大吃一惊,修改后测试通过率下降了近5%。我知道单元测试已经覆盖了所有新的代码,究竟哪里出了问题?比较测试报告时,一位同事敏锐地发现修改hashCode()前这些测试都没有问题。当然,这是有道理的:默认toString()会调用hashCode():

public String toString() {
    
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

覆盖toString()后,自定义实现不再调用hashCode()。这里缺少一个测试。

大家都知道toString()的默认实现,但是……

hashCode()的默认实现是怎样的?

默认hashCode()返回值被称作identity hash code。接下来的文章中,我会用这个术语把它与重写后的hashCode()返回的哈希值进行区分。仅供参考:即使重写了hashCode(),还可以调用System.identityHashCode(o)得到对象的identity hash code。

众所周知,identity hash code使用了内存地址的整数表示。这也是J2SE JavaDocs中关于Object.hashCode()的描述:

...通常把对象内部地址

转换为整数,但这种实现不是 

Java™语言本身的要求。

这种实现似乎由问题,因为方法的定义要求:

执行Java程序时,在同一对象上多次调用

hashCode方法结果必须

返回相同的整数。

鉴于JVM会重定位对象(例如,在垃圾回收周期可能发生提升或压缩),因此在对象identity hash计算完成后需要能够确保不受重定位影响。

一种可能是首次调用hashCode()时获得对象当前内存位置,与对象一起保存在某个地方,比如对象头。这样,即使对象被移到内存其它地方也会保留原来的哈希值。采用这种方法需要注意一点,可能产生两个对象具有相同的identity hash,但这是规范允许的。

最好办法是通过源代码确认。不幸的是,默认的java.lang.Object::hashCode() 是一个原生函数:

public native int hashCode();

开始行动。

能否找到真正的hashCode()?

注意:hashCode()实现与JVM相关。本文只讨论OpenJDK源代码,下文中出现JVM时都特指OpenJDK。源代码请参考Hotspot tree中的changeset 5820:87ee5ee27509。尽管大部分实现在Oracle JVM上应该也使用,但其实际可能会有区别。

OpenJDK在src/share/vm/prims/jvm.h和src/share/vm/prims/jvm.cpp中定义了hashCode()入口。jvm.cpp中:

508 JVM_ENTRY(jint, JVM_IHashCode(JNIEnv* env, jobject handle))
509 JVMWrapper("JVM_IHashCode");
510 // 在经典虚拟机中实现;如果对象为NULL,则返回0
511 return handle == NULL ? 0 : ObjectSynchronizer::FastHashCode (THREAD, JNIHandles::resolve_non_null(handle)) ;
512 JVM_END

ObjectSynchronizer::FastHashCode()还被identity_hash_value_for调用,后者有几个地方会调用(例如:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值