由于对象的默认哈希值是对象的对象地址,因此在32位机器上,考虑到哈希值是一个int值,这是有道理的。我的问题是在64位机器上,地址应该是64位对吗?那么32位int哈希值怎么样?是否会有一些下转换(从64位到32位)?
答案 0 :(得分:15)
如何计算标识hashCode是特定于JVM的。
对于HotSpot JVM,它使用随机数生成器进行身份hashCode的初始计算。在第一次计算hashCode之后,它会保存在对象头中,以便后续调用identityHashCode
将返回相同的值。
实际上,生成标识hashCode的算法可以通过-XX:hashCode
JVM选项进行更改。看看the sources。有以下选项:
-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 -XX:hashCode=5
- 线程本地Marsaglia的Xor-shift RNG (自Java 8起默认) 答案 1 :(得分:6)
我的问题是64位JVM上对象的默认哈希值是多少?它仍然是对象地址值吗?
“默认”值...或者更具体地说,如何计算对象的“身份哈希码”是未指定的。不在32位JVM或64位JVM上。
据观察,该值通常是基于对象的地址,即System.identityHashcode()
方法首先被调用,但这只是一个观察。当然 not 被指定为,这意味着不同的JVM可以自由地以不同方式实现它。
当然,它不能是64位JVM上的实际地址......因为64位地址不适合32位整数。明显。
然而,实际上计算的是,身份哈希码仍然是 NEVER 对象地址的可靠代理。如果具有标识哈希码的对象在垃圾收集周期中存活,则GC 可能已移动它,并且其哈希码和地址此后将不相关。 (有一点可以保证,对象的标识哈希码不会改变。如果确实如此,哈希表就会破坏。)
答案 2 :(得分:3)
在OpenJDK / HotSpot JVM中,您可以获取引用的原始索引地址。这转换为小堆的32位地址和大堆的64位地址。对于中型堆,使用32位Compressed OOPS。
实施在synchronizer.cpp AFAIK中可用,最后一个实现是实际使用的。
/**
* Prints the addresses and hashCode()s of the first objects in eden space.
* <p>
* Assumes a 32-bit address space e.g. CompressOops
* </p>
*/
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
8
开始到F
。答案 3 :(得分:1)
在Java中,int
是32位。即使在64位本机上也是如此。见Integer.SIZE
。此外,Oracle的Primitive Data Types教程(部分) -
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 编程语言不需要此实现技术。)
答案 4 :(得分:1)
据我所知和测试,在压缩oops模式下从JVM内部地址获取本机地址的最可靠方法是使用&#34; getNarrowOopBase&#34; 和< strong>&#34; getNarrowOopShift&#34; &#34; sun.jvm.hotspot.memory.Universe&#34; 类的方法,如果使用该类,该类可用&#34; Java HotSpot Serviceability Agent&#34; 。
原生地址可以计算为:
if (compressedRef) {
return (address >> compressRefShift) - compressRefBase;
}
else {
return address;
}
以下是它的用法