是否有可能在Java中获取对象的物理地址?

时间:2016-09-24 19:21:18

标签: java

引用变量存储对象的引用。看来获取此引用的唯一方法是调用toString()方法,该方法返回对象哈希码而不是地址。有没有办法获得对象的物理地址?

class Point {
int x;
int y;
}
public class MyClass {
    public static void main(String[] args) {
    Point p = new Point();
}
}

我的问题是:“是否有可能获得p对象的物理地址?”。当然我知道p.toString()返回其哈希码。这就是我要问有可能获得地址的原因。我不需要使用它或更改它。我只需要知道是否有可能得到它。

我提出问题的原因是我在许多不同的地方看到了很多相同的问题,但没有答案。我只需要确认我的建议是不可能的。但在这种情况下,出现了一个新问题:JVM如何找到对象?

1 个答案:

答案 0 :(得分:0)

  

。看来获取此引用的唯一方法是调用toString()方法,该方法返回对象哈希码而不是地址。

hashCode是一个随机生成的数字,与地址无关。

  

有没有办法获得对象的物理地址?

你可以使用Unsafe来获取它,但你不应该为兴趣以外的任何事情做这件事。

  

JVM如何找到对象?

JVM使用引用作为索引。该索引可以是间接的,即可以存在对象所在的数组,它可以是例如翻译。 CompressedOops可能会将索引乘以8,并可选择添加偏移量。

如果使用Oracle / OpenJDK并禁用CompressedOops,则可以获得未翻译的64位地址。

一种简单的方法是将对象的地址放入数组中 然后根据引用的大小访问数组的元素,就好像它们是intlong一样。

Object i = 0x12345678;
System.out.printf("indentityHashCode = %08x%n", System.identityHashCode(i));
Object[] obj = {i};
assert Unsafe.ARRAY_OBJECT_INDEX_SCALE == 8; // 8 bytes per reference.
long address = UNSAFE.getLong(obj, (long) Unsafe.ARRAY_OBJECT_BASE_OFFSET);
System.out.printf("%x%n", address);
for (int j = 0; j < 24; j++)
    System.out.printf("%02x ", UNSAFE.getByte(address + j) & 0xFF);
System.out.println();

// now some really scary sh!t
UNSAFE.putLong(i, 8L, UNSAFE.getLong(0L, 8L));
System.out.printf("`i` is now a %s and is %x%n", i.getClass(), i);

我在这里有很多其他的例子

https://github.com/peter-lawrey/Performance-Examples/tree/master/src/main/java/vanilla/java/unsafe

最有用的技巧之一是能够在GC之前和之后查看对象的排列方式。只在家尝试这个。 NSFW。