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

原文地址: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来获取类的内存地址了,敬请期待!!!

第2章 使用的基本技术及工具 2.1 开发环境 开发平台:Windows10; 数据库:MySQL; JDK:1.7 及以上; 编程语言:Java; 开发根工具:Android Studio 2022 运行设备:android 手机或虚拟机。 2.2 使用的技术及工具介绍 2.2.1 Spring 框架 Android是谷歌旗下著名的移动开源操作系统。这个系统的内核是Linux。 该系统具有很高的兼容性,可以用在包括智能手机、电视、平板等诸多设备上。有着高度兼容的特性。最重要的是,Android开源的属性使开发者可以自由的通过Android系统进行开发。而本系统就是基于Android开发的一款医院挂号系统。Android的开源属性在07年已经推出,就受到了开发者的高度赞扬,而Android开发也成为一时间最热门的词语。开发者可以在Android系统上尽情挥舞画笔随心所欲地创作。Android作为以智能手机、平板、电视为主战场的可移动设备操作系统,使用度适用性常广泛,远远超过诸如塞班、IOS等系统。在Android平台上,APP的体系结构很大幅度的上简化了组件的工作。在这之中,Java成为了APP开发的唯一语言,Java通过跨平台功能,无需编译基于Android框架开发的软件应用程序,即任意一台搭载了Android的设备均可运行。 2.2.2 SQLite介绍 SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。它的设计目标是嵌入式的,而且已经在很多嵌入式产品中使用了它,它占用资源常的低,在嵌入式设备中,可能只需要几百K的内存就够了。它能够支持Windows/Linux/Unix等等主流的操作系统,同时能够跟很多程序语言相结合,比如PHP、Java等,还有ODBC接口,同样比起MySQL、PostgreSQL这两款开源的世界著名数据库管理系统来讲,它的处理速度比他们都快。SQLite第一个Alpha版本诞生于2000年5月。 至2021年已经接近有21个年头,SQLite也迎来了一个版本 SQLite 3已经发布。 2.2.3 B/S架构介绍 B/S结构是目前使用最多的结构模式,它可以使得系统的开发更加的简单,好操作,而且还可以对其进行维护。使用该结构时只需要在计算机中安装数据库,一些很常用的浏览器就可以了。浏览器就会与数据库进行信息的连接,可以实现很多的功能,B/S结构是可以直接进行使用的,而且B/S结构在使用中极大的减少了工作的维护。基于B/S的软件,所有的数据库之间都是相互独立的,因此是安全的。因为基于B/S结构可以清楚的看到系统正在处理的业务,并且能够及时的让管理人员做出决策,这样就可以避免企业的损失。B/S结构的基本特点是集中式的管理模式,用户使用系统生成数据后,这些数据就可以存储到系统的数据库中,方便日后能够用到,这样就可以满足人们的所有的需求。 2.2.4 Java语言介绍 Java是由SUN公司推出,该公司于2010年被oracle公司收购。Java本是印度尼西亚的一个叫做爪洼岛的英文名称,也因此得来java是一杯正冒着热气咖啡的标识。Java语言在移动互联网的大背景下具备了显著的优势广阔的前景,它是面向对象的,分布式的,动态的,具有平台无关性、安全性、健壮性。Java语言的基本语句语法C++一样,但是它面向对象的技术更加彻底,因为Java要求将所有的内容都必须封装成,把作为程序的基本单位。由于允许外有变量、方法。 Java语言的分布式体现在数据分布操作分布,它是面向网络的语言,可以处理TCP/IP协议,它也支持客户机/服务器的计算模式。Java语言的动态性是指在运行时是动态安装的,使得Java可以动态的维护程序。Java支持指针,对内存访问的所有操作都是通过对象实例化实现的,这样就避免了指针操作中易产生的错误,同时也预防了病毒对系统的破坏威胁。 Java语言的编程风格与C语言常接近,它继承了C++面向对象技术的核心,它面世之后发展迅速,常流行,对高级C语言形成了很大的冲击。业内人士称之为“一次编译、到处执行”。当然java也有缺点,在每次执行编译后,字节码都需要消耗一定的时间,在某些程度上降低了性能。但是这并影响java成为此次设计语言的选择。Java语言简单易学,使用它的编程时间短,功能性强,开发者学习起来更简便、更快。Java的主要特性有以下几个: (1)面向对象 面向对象有四个特点:封装、继承、多态、抽象。抽象是指忽略一个问题中的次要部分,关注主要部分。多态是指对同一种消息做出的同反应。继承是指在原有的父方法基础上增加自己独有的方法,而改变原来父。 (2)平台无关性 Java编译出来的是字节码,直接由虚拟机执行。在任何平台上,只要有Java虚拟机,Java代码都能运行。 (3)可靠性安全Java内存的访问都必须通过对象的实例变量来实现,避免了指针中出现的错误。 (4)多线程 Java提供了多线程功能,利用编程实现同一时间同时工作的功能。 以这样的形式写出一段基于ssm的图书管理系统文档
最新发布
06-17
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值