什么是64位JVM上对象的默认哈希值

由于对象的默认哈希值是对象的对象地址,因此在32位机器上,考虑到哈希值是一个int值,这是有道理的。 我的问题是在64位机器上,地址应该是64位对吗? 那么32位int哈希值怎么样? 是否会有一些下转换(从64位到32位)?

我的问题是64位JVM上对象的默认哈希值是多少? 它仍然是对象地址值吗?

“默认”值…或更具体地说,如何计算对象的“身份哈希码”是不是指定的。 不在32位JVM或64位JVM上。

据观察,该值通常基于 首次调用System.identityHashcode()方法的对象地址,但这只是一个观察。 当然没有指定它,这意味着不同的JVM可以自由地以不同方式实现它。

当然,它不能是64位JVM上的实际地址…因为64位地址不适合32位整数。 明显。


然而,它实际上是计算的,它仍然是身份哈希码永远不是对象地址的可靠代理的事实。 如果具有标识哈希码的对象在垃圾收集周期中存活,则GC 可能已经移动它,并且其哈希码和地址将在此后不相关。 (保证的一件事是对象的标识哈希码不会改变。如果确实如此,哈希表就会中断。)

如何计算标识hashCode是特定于JVM的。

对于HotSpot JVM,它使用随机数生成器来初始计算身份hashCode。 在第一次计算hashCode之后,它将保存在对象头中,以便后续对identityHashCode调用将返回相同的值。

实际上,生成标识hashCode的算法可以通过-XX:hashCode JVM选项进行更改。 看看消息来源 。 有以下选项:

  • -XX:hashCode=0 – 全局Park-Miller RNG (默认为Java 7)
  • -XX:hashCode=1 – function(obj_address,global_state)
  • -XX:hashCode=2 – 常量1.所有对象都具有相同的hashCode。 只是为了测试。
  • -XX:hashCode=3 – 增量计数器。
  • -XX:hashCode=4 – Heap中对象地址的低32位
  • -XX:hashCode=5 – 线程局部Marsaglia的Xor-shift RNG (自Java 8起默认)

在OpenJDK / HotSpot JVM中,您可以获取引用的原始索引地址。 这转换为小堆的32位地址和大堆的64位地址。 对于中型堆,使用32位压缩OOPS 。

该实现在synchronizer.cpp AFAIK中可用,最后一个实现是实际使用的实现。

 /** * Prints the addresses and hashCode()s of the first objects in eden space. * 

* Assumes a 32-bit address space eg CompressOops *

*/ public static void main(String... ignored) throws Exception { Object[] objects = new Object[8]; for (int i = 0; i < 20; i++) { System.gc(); for (int j = 0; j < objects.length; j++) { objects[j] = new Object(); } for (int j = 0; j < objects.length; j++) { long address = OBJECT_SCALE == 4 ? UNSAFE.getInt(objects, OBJECT_BASE + j * OBJECT_SCALE) & 0xFFFFFFFFL : UNSAFE.getLong(objects, OBJECT_BASE + j * OBJECT_SCALE); System.out.printf("%,d: addr: %8x, hc: %8x ", j, address, objects[j].hashCode()); } System.out.println(); } } static final Unsafe UNSAFE; static final int OBJECT_BASE, OBJECT_SCALE; static { try { Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); theUnsafe.setAccessible(true); UNSAFE = (Unsafe) theUnsafe.get(null); OBJECT_BASE = UNSAFE.arrayBaseOffset(Object[].class); OBJECT_SCALE = UNSAFE.arrayIndexScale(Object[].class); } catch (Exception e) { throw new AssertionError(e); } }

版画

 0: addr: fc000000, hc: 6d6f6e28 1: addr: fc000001, hc: 29453f44 2: addr: fc000002, hc: 5cad8086 3: addr: fc000003, hc: 6e0be858 4: addr: fc000004, hc: 61bbe9ba 5: addr: fc000005, hc: 610455d6 6: addr: fc000006, hc: 511d50c0 7: addr: fc000007, hc: 60e53b93 0: addr: fc000000, hc: 5e2de80c 1: addr: fc000001, hc: 1d44bcfa 2: addr: fc000002, hc: 266474c2 3: addr: fc000003, hc: 6f94fa3e 4: addr: fc000004, hc: 5e481248 5: addr: fc000005, hc: 66d3c617 6: addr: fc000006, hc: 63947c6b 7: addr: fc000007, hc: 2b193f2d 0: addr: fc000000, hc: 355da254 1: addr: fc000001, hc: 4dc63996 2: addr: fc000002, hc: d716361 3: addr: fc000003, hc: 6ff3c5b5 4: addr: fc000004, hc: 3764951d 5: addr: fc000005, hc: 4b1210ee 6: addr: fc000006, hc: 4d7e1886 7: addr: fc000007, hc: 3cd1a2f1 0: addr: fc000000, hc: 2f0e140b 1: addr: fc000001, hc: 7440e464 2: addr: fc000002, hc: 49476842 3: addr: fc000003, hc: 78308db1 4: addr: fc000004, hc: 27c170f0 5: addr: fc000005, hc: 5451c3a8 6: addr: fc000006, hc: 2626b418 7: addr: fc000007, hc: 5a07e868 0: addr: fc000000, hc: 76ed5528 1: addr: fc000001, hc: 2c7b84de 2: addr: fc000002, hc: 3fee733d 3: addr: fc000003, hc: 5acf9800 4: addr: fc000004, hc: 4617c264 5: addr: fc000005, hc: 36baf30c 6: addr: fc000006, hc: 7a81197d 7: addr: fc000007, hc: 5ca881b5 0: addr: fc000000, hc: 24d46ca6 1: addr: fc000001, hc: 4517d9a3 2: addr: fc000002, hc: 372f7a8d 3: addr: fc000003, hc: 2f92e0f4 4: addr: fc000004, hc: 28a418fc 5: addr: fc000005, hc: 5305068a 6: addr: fc000006, hc: 1f32e575 7: addr: fc000007, hc: 279f2327 0: addr: fc000000, hc: 2ff4acd0 1: addr: fc000001, hc: 54bedef2 2: addr: fc000002, hc: 5caf905d 3: addr: fc000003, hc: 27716f4 4: addr: fc000004, hc: 8efb846 5: addr: fc000005, hc: 2a84aee7 6: addr: fc000006, hc: a09ee92 7: addr: fc000007, hc: 30f39991 0: addr: fc000000, hc: 452b3a41 1: addr: fc000001, hc: 4a574795 2: addr: fc000002, hc: f6f4d33 3: addr: fc000003, hc: 23fc625e 4: addr: fc000004, hc: 3f99bd52 5: addr: fc000005, hc: 4f023edb 6: addr: fc000006, hc: 3a71f4dd 7: addr: fc000007, hc: 7adf9f5f 0: addr: fc000000, hc: 85ede7b 1: addr: fc000001, hc: 5674cd4d 2: addr: fc000002, hc: 63961c42 3: addr: fc000003, hc: 65b54208 4: addr: fc000004, hc: 1be6f5c3 5: addr: fc000005, hc: 6b884d57 6: addr: fc000006, hc: 38af3868 7: addr: fc000007, hc: 77459877 0: addr: fc000000, hc: 5b2133b1 1: addr: fc000001, hc: 72ea2f77 2: addr: fc000002, hc: 33c7353a 3: addr: fc000003, hc: 681a9515 4: addr: fc000004, hc: 3af49f1c 5: addr: fc000005, hc: 19469ea2 6: addr: fc000006, hc: 13221655 7: addr: fc000007, hc: 2f2c9b19 0: addr: fc000000, hc: 31befd9f 1: addr: fc000001, hc: 1c20c684 2: addr: fc000002, hc: 1fb3ebeb 3: addr: fc000003, hc: 548c4f57 4: addr: fc000004, hc: 1218025c 5: addr: fc000005, hc: 816f27d 6: addr: fc000006, hc: 87aac27 7: addr: fc000007, hc: 3e3abc88 0: addr: fc000000, hc: 6ce253f1 1: addr: fc000001, hc: 53d8d10a 2: addr: fc000002, hc: e9e54c2 3: addr: fc000003, hc: 65ab7765 4: addr: fc000004, hc: 1b28cdfa 5: addr: fc000005, hc: eed1f14 6: addr: fc000006, hc: 7229724f 7: addr: fc000007, hc: 4c873330 0: addr: fc000000, hc: 119d7047 1: addr: fc000001, hc: 776ec8df 2: addr: fc000002, hc: 4eec7777 3: addr: fc000003, hc: 3b07d329 4: addr: fc000004, hc: 41629346 5: addr: fc000005, hc: 404b9385 6: addr: fc000006, hc: 6d311334 7: addr: fc000007, hc: 682a0b20 0: addr: fc000000, hc: 3d075dc0 1: addr: fc000001, hc: 214c265e 2: addr: fc000002, hc: 448139f0 3: addr: fc000003, hc: 7cca494b 4: addr: fc000004, hc: 7ba4f24f 5: addr: fc000005, hc: 3b9a45b3 6: addr: fc000006, hc: 7699a589 7: addr: fc000007, hc: 58372a00 0: addr: fc000000, hc: 4dd8dc3 1: addr: fc000001, hc: 6d03e736 2: addr: fc000002, hc: 568db2f2 3: addr: fc000003, hc: 378bf509 4: addr: fc000004, hc: 5fd0d5ae 5: addr: fc000005, hc: 2d98a335 6: addr: fc000006, hc: 16b98e56 7: addr: fc000007, hc: 7ef20235 0: addr: fc000000, hc: 27d6c5e0 1: addr: fc000001, hc: 4f3f5b24 2: addr: fc000002, hc: 15aeb7ab 3: addr: fc000003, hc: 7b23ec81 4: addr: fc000004, hc: 6acbcfc0 5: addr: fc000005, hc: 5f184fc6 6: addr: fc000006, hc: 3feba861 7: addr: fc000007, hc: 5b480cf9 0: addr: fc000000, hc: 6f496d9f 1: addr: fc000001, hc: 723279cf 2: addr: fc000002, hc: 10f87f48 3: addr: fc000003, hc: b4c966a 4: addr: fc000004, hc: 2f4d3709 5: addr: fc000005, hc: 4e50df2e 6: addr: fc000006, hc: 1d81eb93 7: addr: fc000007, hc: 7291c18f 0: addr: fc000000, hc: 34a245ab 1: addr: fc000001, hc: 7cc355be 2: addr: fc000002, hc: 6e8cf4c6 3: addr: fc000003, hc: 12edcd21 4: addr: fc000004, hc: 34c45dca 5: addr: fc000005, hc: 52cc8049 6: addr: fc000006, hc: 5b6f7412 7: addr: fc000007, hc: 27973e9b 0: addr: fc000000, hc: 312b1dae 1: addr: fc000001, hc: 7530d0a 2: addr: fc000002, hc: 27bc2616 3: addr: fc000003, hc: 3941a79c 4: addr: fc000004, hc: 506e1b77 5: addr: fc000005, hc: 4fca772d 6: addr: fc000006, hc: 9807454 7: addr: fc000007, hc: 3d494fbf 0: addr: fc000000, hc: 1ddc4ec2 1: addr: fc000001, hc: 133314b 2: addr: fc000002, hc: b1bc7ed 3: addr: fc000003, hc: 7cd84586 4: addr: fc000004, hc: 30dae81 5: addr: fc000005, hc: 1b2c6ec2 6: addr: fc000006, hc: 4edde6e5 7: addr: fc000007, hc: 70177ecd 

对于3-30 GB之间的CompressedOops和堆,它可以让您了解内存位置(但它已被翻译)在上面的例子中,地址是index * 8 8来自分配块大小,默认为8个字节。 它可以在Java 8中增加到16或32,尽管使用16仅对32 - 64 GB的堆有用,32可能根本不用,因为32字节分配大小可能比使用64位引用更昂贵

如您所见,每个对象都在System.gc()之后分配在同一空间中。 每次地址都相同,但hashCode

  • 与地址没什么关系
  • 只有31位,没有以hex从8F开始。

在Java中, int是32位。 即使在64位本机上也是如此。 请参见Integer.SIZE 。 此外,Oracle的原始数据类型教程(部分)说 –

int:默认情况下,int数据类型是32位带符号的二进制补码整数,其最小值为-2 31 ,最大值为2 31 -1。 在Java SE 8及更高版本中,您可以使用int数据类型来表示无符号的32位整数,其最小值为0,最大值为2 32 -1。 使用Integer类将int数据类型用作无符号整数。 有关详细信息,请参阅“数字类”一节。 已经将诸如compareUnsigned,divideUnsigned等静态方法添加到Integer类中,以支持无符号整数的算术运算。

Object#hashCode() Javadoc说,

(这通常通过将对象的内部地址转换为整数来实现,但Java TM编程语言不需要此实现技术。)

据我所知和测试,在压缩oops模式下从JVM内部addess获取本机地址的最可靠方法是使用“sun.jvm.hotspot.memory.Universe”的“getNarrowOopBase”“getNarrowOopShift”方法在使用“Java HotSpot Serviceability Agent”的情况下,类和该类可用。

本地地址可以计算为:

 if (compressedRef) { return (address >> compressRefShift) - compressRefBase; } else { return address; } 

以下是它的用法

https://github.com/serkan-ozal/jillegal/blob/master/src/main/java/tr/com/serkanozal/jillegal/util/HotspotJvmInfoUtil.java

https://github.com/serkan-ozal/jillegal/blob/master/src/main/java/tr/com/serkanozal/jillegal/util/JvmUtil.java