有没有办法获取参考地址?
在Java中,有没有办法获得参考地址,比如说
String s = "hello"
我可以获得s本身的地址,也可以得到引用所引用的对象的地址吗?
在Java中,有没有办法获得参考地址,比如说
String s = "hello"
我可以获得s本身的地址,也可以得到引用所引用的对象的地址吗?
您可以使用 Unsafe 获取对象索引。根据 JVM 使用内存的方式(32 位地址、32 位索引、带偏移的 32 位索引、64 位地址)会影响对象索引的有用程度。
下面是一个程序,它假设您在 64 位 JVM 中有 32 位索引。
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);
}
}
}
在 Java 6 update 26(64 位,带压缩 oops)和 Java 7 上运行。注意:地址和相对地址以十六进制表示。
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
或有时
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
是的,你可以用不安全来做,虽然它不是那么直接。将对象或实例引用放入 int[] 中,这没关系。long[] 也应该没问题。
@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;
}