What's the default hash value of an object on 64 bit JVM

后端 未结 5 1665
慢半拍i
慢半拍i 2020-12-17 07:40

Since default hash value of an object is the object address of the object, on 32-bit machine, it makes sense considering hash value is an int value. My question is that on 6

相关标签:
5条回答
  • 2020-12-17 07:45

    In the OpenJDK/HotSpot JVM you can obtain the raw index address of a reference. This translates to a 32-bit address for a small heap and a 64-bit address for a large heap. For medium sized heaps, 32-bit Compressed OOPS are used.

    The implementation is available in synchronizer.cpp AFAIK, the last implementation is the one actually used.

    /**
     * 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);
        }
    }
    

    prints

    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 
    

    For CompressedOops and heaps between 3-30 GB, it gives you an idea of the memory location (but it is translated) In the case above, the addresses are index * 8 The 8 comes from the allocation block size which is 8 bytes by default. It can be increased to 16 or 32 in Java 8, although using 16 is only useful for heaps of 32 - 64 GB, and 32 might not be useful at all as a 32 byte allocation size might be more expensive than using 64-bit references

    As you can see, each object was allocated in the same space after a System.gc(). The addresses are the same each time, however the hashCode

    • has little to do with the address
    • is only 31-bit, there is nothing starting 8 to F in hexadecimal.
    0 讨论(0)
  • 2020-12-17 07:49

    How to calculate identity hashCode is JVM specific.

    As to HotSpot JVM, it uses random number generator for initial calculation of identity hashCode. After the hashCode is calculated for the first time, it is saved in the object header so that subsequent calls to identityHashCode will return the same value.

    Actually the algorithm of generating identity hashCode can be altered by -XX:hashCode JVM option. Look at the sources. There are the following options:

    • -XX:hashCode=0 - global Park-Miller RNG (default until Java 7)
    • -XX:hashCode=1 - function(obj_address, global_state)
    • -XX:hashCode=2 - constant 1. All objects will have the same hashCode. Just for testing.
    • -XX:hashCode=3 - incremental counter.
    • -XX:hashCode=4 - lower 32 bits of the object address in the Heap
    • -XX:hashCode=5 - thread-local Marsaglia's Xor-shift RNG (default since Java 8)
    0 讨论(0)
  • 2020-12-17 08:02

    My question is that what's the default hash value for an object on 64 bit JVM? Is it still the object address value?

    The "default" value ... or more specifically how an object's "identity hashcode" is calculated is NOT SPECIFIED. Not on a 32bit JVM, or a 64bit JVM.

    It is observed that the value is typically based on the object's address at the point that the System.identityHashcode() method is first called, but that is only an observation. It is certainly not specified to be that, which means that different JVMs are free to implement it differently.

    Certainly, it cannot be the actual address on a 64bit JVM ... since a 64 bit address won't fit into a 32 bit integer. Obviously.


    However it is actually calculated, it remains the fact that the identity hashcode is NEVER a reliable proxy for the object's address. If an object with an identity hashcode survives a garbage collection cycle, the GC will probably have moved it, and its hashcode and address will henceforth be unrelated. (One thing that is guaranteed is that an object's identity hashcode does not change. If it did, hash tables would break.)

    0 讨论(0)
  • 2020-12-17 08:02

    In Java an int is 32-bits. Even on a 64-bit native machine. See Integer.SIZE. Also, Oracle's Primitive Data Types Tutorial says (in part) -

    int: By default, the int data type is a 32-bit signed two's complement integer, which has a minimum value of -231 and a maximum value of 231-1. In Java SE 8 and later, you can use the int data type to represent an unsigned 32-bit integer, which has a minimum value of 0 and a maximum value of 232-1. Use the Integer class to use int data type as an unsigned integer. See the section The Number Classes for more information. Static methods like compareUnsigned, divideUnsigned etc have been added to the Integer class to support the arithmetic operations for unsigned integers.

    The Object#hashCode() Javadoc says,

    (This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the JavaTM programming language.)

    0 讨论(0)
  • 2020-12-17 08:08

    As far as I know and test, the most reliable way to get native address from JVM internal addess in case of compressed-oops mode, is using "getNarrowOopBase" and "getNarrowOopShift" methods of "sun.jvm.hotspot.memory.Universe" class and that class can be available in case of using "Java HotSpot Serviceability Agent".

    Native address can be calculated as:

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

    Here are usages of it

    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

    0 讨论(0)
提交回复
热议问题