Is there a way to get a reference address?
Solution 1
You can get the object index with Unsafe. Depending on how the JVM is using the memory (32-bit addresses, 32-bit index, 32-bit index with offset, 64-bit address) can affect how useful the object index is.
Here is a program which assumes you have 32-bit index in a 64-bit JVM.
import sun.misc.Unsafe;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Collections;
public class OrderOfObjectsAfterGCMain {
static final Unsafe unsafe = getUnsafe();
static final boolean is64bit = true; // auto detect if possible.
public static void main(String... args) {
Double[] ascending = new Double[16];
for(int i=0;i<ascending.length;i++)
ascending[i] = (double) i;
Double[] descending = new Double[16];
for(int i=descending.length-1; i>=0; i--)
descending[i] = (double) i;
Double[] shuffled = new Double[16];
for(int i=0;i<shuffled.length;i++)
shuffled[i] = (double) i;
Collections.shuffle(Arrays.asList(shuffled));
System.out.println("Before GC");
printAddresses("ascending", ascending);
printAddresses("descending", descending);
printAddresses("shuffled", shuffled);
System.gc();
System.out.println("\nAfter GC");
printAddresses("ascending", ascending);
printAddresses("descending", descending);
printAddresses("shuffled", shuffled);
System.gc();
System.out.println("\nAfter GC 2");
printAddresses("ascending", ascending);
printAddresses("descending", descending);
printAddresses("shuffled", shuffled);
}
public static void printAddresses(String label, Object... objects) {
System.out.print(label + ": 0x");
long last = 0;
int offset = unsafe.arrayBaseOffset(objects.getClass());
int scale = unsafe.arrayIndexScale(objects.getClass());
switch (scale) {
case 4:
long factor = is64bit ? 8 : 1;
final long i1 = (unsafe.getInt(objects, offset) & 0xFFFFFFFFL) * factor;
System.out.print(Long.toHexString(i1));
last = i1;
for (int i = 1; i < objects.length; i++) {
final long i2 = (unsafe.getInt(objects, offset + i * 4) & 0xFFFFFFFFL) * factor;
if (i2 > last)
System.out.print(", +" + Long.toHexString(i2 - last));
else
System.out.print(", -" + Long.toHexString( last - i2));
last = i2;
}
break;
case 8:
throw new AssertionError("Not supported");
}
System.out.println();
}
private static Unsafe getUnsafe() {
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
return (Unsafe) theUnsafe.get(null);
} catch (Exception e) {
throw new AssertionError(e);
}
}
}
Running on Java 6 update 26 (64-bit with compressed oops) and Java 7. Note: addresses and relative addresses are in hex.
Before GC
ascending: 0x782322b20, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18
descending: 0x782322e58, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18
shuffled: 0x782322ec0, +78, -30, +90, -c0, +18, +90, +a8, -30, -d8, +f0, -30, -90, +60, -48, +60
After GC
ascending: 0x686811590, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18
descending: 0x686811410, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18
shuffled: 0x686811290, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18
OR sometimes
Before GC
ascending: 0x782322b20, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18
descending: 0x782322e58, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18
shuffled: 0x782323028, -168, +150, -d8, -30, +60, +18, +30, +30, +18, -108, +30, -48, +78, +78, -30
After GC
ascending: 0x6868143c8, +4db0, +7120, -bd90, +bda8, -bd90, +4d40, +18, +18, -12710, +18, +80, +18, +ffa8, +220, +6b40
descending: 0x68681d968, +18, +d0, +e0, -165d0, +a8, +fea8, +c110, -5230, -d658, +6bd0, +be10, +1b8, +75e0, -19f68, +19f80
shuffled: 0x686823938, -129d8, +129f0, -17860, +4e88, +19fe8, -1ee58, +18, +18, +bb00, +6a78, -d648, -4e18, +4e40, +133e0, -c770
Solution 2
Yes, You can do it with Unsafe, Althrough it's not so directly. Put the object or instance reference into a int[], that's ok. long[] should be fine as well.
@Test
public void test1() throws Exception {
Unsafe unsafe = Util.unsafe;
int base = unsafe.arrayBaseOffset(int[].class);
int scale = unsafe.arrayIndexScale(int[].class);
int shift = 31 - Integer.numberOfLeadingZeros(scale);
System.out.printf("base: %s, scale %s, shift: %s\n", base, scale, shift);
base = unsafe.arrayBaseOffset(Object[].class);
scale = unsafe.arrayIndexScale(Object[].class);
shift = 31 - Integer.numberOfLeadingZeros(scale);
System.out.printf("base: %s, scale %s, shift: %s\n", base, scale, shift);
int[] ints = { 1, 2, 0 };
String string = "abc";
System.out.printf("string: id: %X, hash: %s\n", System.identityHashCode(string), string.hashCode());
unsafe.putObject(ints, offset(2, shift, base), string);
System.out.printf("ints: %s, %X\n", Arrays.toString(ints), ints[2]);
Object o = unsafe.getObject(ints, offset(2, shift, base));
System.out.printf("ints: %s\n", o);
assertSame(string, o);
Object[] oa = { 1, 2, string };
o = unsafe.getObject(oa, offset(2, shift, base));
assertSame(string, o);
int id = unsafe.getInt(oa, offset(2, shift, base));
System.out.printf("id=%X\n", id);
}
public static long offset(int index, int shift, int base) {
return ((long) index << shift) + base;
}
Solution 3
No, you cannot. Even using the Java Native Interface (JNI), you can only get an opaque handle to the data structure, not a pointer to the real JVM object.
Why would you want such a thing? It wouldn't necessarily be in a form you could use for anything, anyway, even from native code.
Solution 4
Actually address can be obtained with sun.misc.Unsafe but it is really very unsafe. GC often moves objects.
Solution 5
It's not possible in Java to get a reference address of an object, like your String. The reference address of an object is hidden to the user, in Java.
In C, you can do this, through the concept of pointers. Java has a similar concept, at low-level,and this is the reference address. The reference is like a C pointer, but it's not explicit. In C, you can do the operation of referencing of pointers, through the *
, but in Java, it's not possible.
I don't like very much the C language, also because the pointers, according to me, are not an easy concept to manage. This is one of the reasons I like Java, because the programmer doesn't need to worry about the pointer of an object.
Like @jarnbjo says, you can check, if some references are similar, with a syntax like this:
String s = "hello";
String g = s;
System.out.println("Are the reference addresses similar? "+(s==g));
g = "goodbye";
System.out.println("Are the reference addresses similar? "+(s==g));
Note that ==
checks the equality of reference address. If you want to check the equality of the value of the strings, use the equals()
method.
I suggest you to read this SO question, this Wikipedia page and this page.
Adam Lee
Updated on April 12, 2020Comments
-
Adam Lee about 4 years
In Java, is there a way to get reference address, say
String s = "hello"
can I get the address of s itself , also, can I get the address of the object which reference refers to?
-
Adam Lee over 12 yearsJust want to make sure some reference are the same.
-
jarnbjo over 12 yearsIf you want to compare two references, you can do that with ==. There's no need for you to get the object's address.
-
Chris Aldrich over 12 years++ good job. Was going to point this out from another SO link: stackoverflow.com/questions/5574241/…, but you showed how to do it with code so even better.
-
Chris Aldrich over 12 yearsThe link I posted in my comment to Peter Lawry shows how you can do it, such that you can retain correct addresses (cause if you create objects using memory allocation, you can probably technically get outside the heap, where GC won't affect you). I'm guessing that is how Terracotta's BigMemory works.
-
Ernest Friedman-Hill over 12 yearsThis is neat stuff, but readers should take care to realize that this is not portable; the
Unsafe
class is an undocumented implementation detail of Sun-derived JVMs. This code won't work on J9, JRockit, Dalvik, etc. -
dawnstar about 11 years@PeterLawrey Is there any detailed explanation about the 32-bit and 64-bit thing? I am pretty interested in that.
-
Vishy about 11 years@dawnstar Here is a good link on that wikis.oracle.com/display/HotSpotInternals/CompressedOops
-
Koray Tugay over 9 yearsWhat are the packages of these classes?
-
qinxian over 7 yearssun.misc.Unsafe. hg openjdk.java.net. jdk\src\share\classes\sun\misc\Unsafe.java