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

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

原文地址:https://zeroturnaround.com/rebellabs/dangerous-code-how-to-be-unsafe-with-java-classes-objects-in-memory/
https://zeroturnaround.com/wp-content/uploads/2013/11/Screen-Shot-2013-11-19-at-2.41.08-PM.png

Java的类和对象在内存里到底是什么样子的呀?我们一起来搞搞清楚撒。。。

你是否对Java内存管理机制感到好奇?有没有问过下面这些奇怪的问题呀:

  • 一个类在内存里占多少空间?
  • 自己写的对象又要占用多大内存?
  • 对象里的属性又是如何对齐的?

如果你思考过这些问题的话,那么你算是来对地方了。对于我们这些在RebelLabs的Java极客们来说,这些神奇的问题一直在诱惑着我们:如果你有兴趣知道更多类的实现的相关知识,知道更多类的布局结构(layout)会让我们从内存里取出特定域的值变得更加容易,甚至我们可以在内存里为所欲为(Hecker的必备技能哦。。。)。这也就是说,我们能不仅更改内存里的数据,也可以在内存里更改代码

另外,如果你知道了这些知识,那么你就具备了理解“Off-heap存储”和“高性能序列化”技术实现的能力。这两个技术是基于内存对象结构操作的典型应用呀! 这篇文章涵盖了获取类和对象的内存地址的方法,获取类和对象在内存里的布局结构,和布局结构中各个域的意义。我们希望能尽可能简单明了地讲明,但是说实话,本文不适合Java初学者。读者需要具备一些Java编程的经验才能读懂。

注意啊!!

本文介绍的类和对象是Java SE7的实现,千万不要认为之前和以后的Java版本也是这么实现的呀!! 我们已经把例子代码放到了GitHub上,可以方便你下载参考。代码在这里


Java里的直接内存访问的方法

Java最初被设计为一种安全受控的环境。然而(重点来啦),Java HotSpot VM在实现的时候留了一个”后门“。这个后门提供了很多可以直接对内存和线程操作的底层接口。这个后门就是——sum.misc.Unsafe。这个类可是被广泛地被JDK本身实现过程应用,比如java.nio和java.util.concurrent的实现。可是,这个后门不建议在生产环境中使用,因为这个API非常不安全、不轻便也不稳定。Unsafe这个类提供了一种窥探HotSpot JVM内部实现的方法,并且可以用一些取巧地方法搞些事情。有时它可以被用来研究VM内部机制,并且不用C++调试哦。有时它可以用于分析和开发工具。


操练起来吧!!

sun.misc.Unsafe这个类真的很不安全,所以JDK的开发人员增加了一些检测机制来限制人们使用它。它的构造函数是私有的,并且它的工厂方法getUnsafe()应该被Bootloader加载。从下面代码段的第8行可知,Unsafe类甚至都不能任何非空的类加载器加载。它会抛出SecurityException异常来阻止访问者。

public final class Unsafe {
   ...
   private Unsafe() {}
   private static final Unsafe theUnsafe = new Unsafe();
   ...
   public static Unsafe getUnsafe() {
      Class cc = sun.reflect.Reflection.getCallerClass(2);
      if (cc.getClassLoader() != null)
          throw new SecurityException("Unsafe");
      return theUnsafe;
   }
   ...
}

幸运地是,在Unsafe里有一个theUnsafe的域可以被用来获取Unsafe对象。我们可以通过反射机制写一个帮助方法帮助实现我们的愿望。代码如下:(http://highlyscalable.wordpress.com/2012/02/02/direct-memory-access-in-java/)

public static Unsafe getUnsafe() {
   try {
           Field f = Unsafe.class.getDeclaredField("theUnsafe");
           f.setAccessible(true);
           return (Unsafe)f.get(null);
   } catch (Exception e) { 
       /* ... */ 
   }
}

Unsafe中一些有用的特性

  1. 虚拟机的固有的特性。就像CAS(compare-and-swap)技术被用于无锁哈希表(Lock-Free Hash Table)。比如,compareAndSwapInt方法使得JNI调用支持特定CAS指令的Native代码。想要了解更多CAS的知识,请点这里
  2. 我们可以使用sun.misc.Unsafe的allocateIntance方法在宿主VM内为未初始化的对象分配内存空间。之后我们可以正常调用这个对象的构造函数。
  3. 我们可以通过实际的内存地址来监测数据。我们用Unsafe是有可能直接查找和修改对象各个域里的值。
  4. 我们还可以使用allocateMemory方法在off-heap中分配内存。比如,当allocateDirect 方法被 调用时DirectByteBuffer的构造函数就调用allocateMemory方法。
  5. arrayBaseOffset arrayIndexScale这两个方法可以用来实现arraylet。Arraylet是一种能将大的数组分解成许多小对象的技术,以减少实时对大对象的检查、更新和删除的开销。

下一篇中,我们要用Unsafe来获取类的内存地址了,敬请期待!!!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值