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

5 篇文章 0 订阅
4 篇文章 0 订阅

原文地址: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);
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值