不安全的代码: 教你“随心所欲”地在内存中操作Java的类和对象(3)

本文介绍了两种在Java中获取Class对象内存地址的方法。一种适用于具体类,利用Unsafe类读取对象内部指向Class的指针;另一种适用于所有类型,包括接口、抽象类等,通过Unsafe类读取Class对象特定偏移位置上的内存地址。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文地址:https://zeroturnaround.com/rebellabs/dangerous-code-how-to-be-unsafe-with-java-classes-objects-in-memory/3/

我们如何得到一个Class在内存中的地址呢?

说实话,要想获取一个Java类在内存中的地址没有什么好的方法。该取巧的地方取巧,该牺牲的东西也要牺牲。下面我们介绍两种方法。


方法1:在JVM中,每个对象都有一个指向其class的指针,但是只有指向实体类的指针,没有指向接口或抽象类的。如果我们得到了一个对象的地址,那么我们就可以很容易地得到其的类的。这种方法只对能实例对象的类受用。接口和抽象类不行!

For 32 bit JVM:
_mark : 4 byte constant
_klass : 4 byte pointer to class

For 64 bit JVM:
_mark : 8 byte constant
_klass : 8 byte pointer to class

For 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);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值