Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why is object location swapped in JVM? [duplicate]

Tags:

java

This is what I tried:

public final class firstObj{    
    public static void main(String args[]){    
        Object obj = new Object();    
        Object obj1 = new Object();    
        System.out.println(obj);
        System.out.println(obj1);    
    }    
}

I compiled the program at first and ran it two consecutive times, I got two different outputs:

output 1:

java.lang.Object@6f548414
java.lang.Object@65ab7626

output 2:

java.lang.Object@659c2931
java.lang.Object@6f548414

I want to know why did the JVM swap the second object's location to first object's location When it ran for the second time.., it is quite bewildering..,

like image 416
Arpan Adhikari Avatar asked Dec 30 '13 16:12

Arpan Adhikari


2 Answers

The hashCode() has little to do with locations in memory. While it might look like an address, it is just a randomly generated number.

i was not expecting it to always allocate from the same segment, but i was wanted to know if the objects were allocated serially, as my output showed a little bit of such pattern

To be expected as it's a random number.


If you run this on OpenJDK or Oracle hotspot, you get.

import sun.misc.Unsafe;

import java.lang.reflect.Field;

public class ObjectAddress {
    public static void main(String[] args) {
        Object o1 = new Object();
        Object o2 = new Object();
        Object o3 = new Object();
        Object[] os = {o1, o2, o3};
        System.out.println("Before using hashCode");
        for (int i = 0; i < os.length; i++) {
            int address = UNSAFE.getInt(os, UNSAFE.arrayBaseOffset(Object[].class) + i * 4);
            int hashCode = UNSAFE.getInt(os[i], 1L);
            System.out.println(i + ": " + Integer.toHexString(address) + " hashCode " + Integer.toHexString(hashCode));
            os[i].hashCode();
        }
        System.out.println("After using hashCode");
        for (int i = 0; i < os.length; i++) {
            int address = UNSAFE.getInt(os, UNSAFE.arrayBaseOffset(Object[].class) + i * 4);
            int hashCode = UNSAFE.getInt(os[i], 1L);
            System.out.println(i + ": " + Integer.toHexString(address) + " hashCode " + Integer.toHexString(hashCode) + " for " + os[i]);
            UNSAFE.putInt(os[i], 1L, 0x12345678);
        }
        System.out.println("After setting the hashCode");
        for (int i = 0; i < os.length; i++) {
            int address = UNSAFE.getInt(os, UNSAFE.arrayBaseOffset(Object[].class) + i * 4);
            int hashCode = UNSAFE.getInt(os[i], 1L);
            System.out.println(i + ": " + Integer.toHexString(address) + " hashCode " + Integer.toHexString(hashCode) + " for " + os[i]);
            os[i].hashCode();
        }

    }

    static final Unsafe UNSAFE;

    static {
        try {
            Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
            theUnsafe.setAccessible(true);
            UNSAFE = (Unsafe) theUnsafe.get(null);
        } catch (Exception e) {
            throw new AssertionError(e);
        }
    }
}

you get something like

Before using hashCode
0: d8e78160 hashCode 0
1: d8e78170 hashCode 0
2: d8e78180 hashCode 0
After using hashCode
0: d8e78160 hashCode 68111f9b for java.lang.Object@68111f9b
1: d8e78170 hashCode 3c322e7d for java.lang.Object@3c322e7d
2: d8e78180 hashCode 3e2f1b1a for java.lang.Object@3e2f1b1a
After setting the hashCode
0: d8e78160 hashCode 12345678 for java.lang.Object@12345678
1: d8e78170 hashCode 12345678 for java.lang.Object@12345678
2: d8e78180 hashCode 12345678 for java.lang.Object@12345678

You can see that each Object is 16 bytes apart.

like image 169
Peter Lawrey Avatar answered Nov 02 '22 20:11

Peter Lawrey


Unlike C, where a request for a new object returns a pointer which will throughout its lifetime be represented with the same unique bit pattern, most Java implementations store references using bit patterns that can change as the program runs (an object reference might store the physical location of an object in memory; if the GC wants to move an object, it will pause all threads, update every single reference to that object which exists anywhere in the universe to point to the new location, and then let threads continue). Having an unchangeable mostly-unique 32-bit number available to describe each object is almost as useful as having an unchangeable 32-bit value which will be totally unique for each live object, or a 64-bit value that could be unique for every object ever created, but is cheaper and easier to implement (keeping a 64-bit value would increase by 8 bytes the storage required for each object, but would have the advantage of establishing a permanent ranking among all objects, which would be useful in some situations such as multiple-lock acquisition or caching; although establishing a permanent ranking for objects is sometimes useful, letting classes which need such ranking implement it themselves is probably better than having the system do it [though it might be helpful to have a system method which if called from multiple threads would return a guaranteed-unique 64-bit number which would be strictly increasing on each thread, and would overall correspond roughly with object age, but which would avoid the cost of an AtomicLong increment]

The hex numbers included in the default string representations of objects are not intended to have any meaning except that any given object will always report the same number, and distinct objects will usually report different numbers. I don't know if there's any particular reason that the numbers appear random-ish rather than counting up from zero and then wrapping, but I would guess that the implementers of Java wanted to discourage people from doing anything that would rely upon objects' hash values having any relationship to each other.

like image 35
supercat Avatar answered Nov 02 '22 18:11

supercat