我们如何得到一个Class在内存中的地址呢?
说实话,要想获取一个Java类在内存中的地址没有什么好的方法。该取巧的地方取巧,该牺牲的东西也要牺牲。下面我们介绍两种方法。
方法1:在JVM中,每个对象都有一个指向其class的指针,但是只有指向实体类的指针,没有指向接口或抽象类的。如果我们得到了一个对象的地址,那么我们就可以很容易地得到其的类的。这种方法只对能实例对象的类受用。接口和抽象类不行!
For 32 bit JVM:
_mark : 4 byte constant
_klass : 4 byte pointer to classFor 64 bit JVM:
_mark : 8 byte constant
_klass : 8 byte pointer to classFor 64 bit JVM with compressed-oops:
_mark : 8 byte constant
_klass : 4 byte pointer to class
上面分别是在32位JVM、64位JVM和打开Compressed Oops选项功能 的64位JVM的内存中,对象部局(layout)的一部分。对象中的每二个域(field)是指向定义类的内存地址。为了得到这个域的值,你可以用“sun.misc.Unsafe”这个类。上一篇中提到的SampleClass在这里的使用方法如下:
For 32 bit JVM:
SampleClass sampleClassObject = new SampleClass();
int addressOfSampleClass = unsafe.getInt(sampleClassObject, 4L);
For 64 bit JVM:
SampleClass sampleClassObject = new SampleClass();
long addressOfSampleClass = unsafe.getLong(sampleClassObject, 8L);
For 64 bit JVM with compressed-oops:
SampleClass sampleClassObject = new SampleClass();
long addressOfSampleClass = unsafe.getInt(sampleClassObject, 8L);
方法2:这个方法可是能获取任务类(包括:接口、匿名类、抽象类和枚举enum)的地址哦!!!在Java7中一个类的实际地址存放是这样的:对于32位JVM来说,放在了从开始80字节间距(原文用的是offset——位移,但是怕读者搞混,所以用了间距来表示。)之后的4个字节里;对于64位JVM来说,是160字节间距后的8个字节里;而对于开启了Compressed Oops的64位JVM来说是84字节间距后的的个字节中。
并且这些间距内没有被定义的内容,但是在文档中却被解析成”隐域”(其中有三个域:class, arrayClass, resolvedConstructor)。这也就是说,它们(地址)恰好就在那个offset下,因为在java.lang.Class中有18个非静态的引用域。
你可以通过ClassFileParser::java_Class_fix_pre()和JavaClasses::check_offsets()了解更多。传送入口:http://hg.openjdk.java.net/jdk7/jdk7/hotspot/file/9b0ca45cd756/src/share/vm/classfile.
用来获取地址的样例代码如下:
For 32 bit JVM:
int addressOfSampleClass = unsafe.getInt(SampleClass.class, 80L);
For 64 bit JVM:
long addressOfSampleClass = unsafe.getLong(SampleClass.class, 160L);
For 64 bit JVM with compressed-oops:
long addressOfSampleClass = unsafe.getInt(SampleClass.class, 84L);