sun.misc.unsafe类的用法
副标题#e#
这个帖子是关于JAVA中鲜为人知的特性的后续更新,假如想获得下次在线接头的更新,请通过邮件订阅,而且不要忘了在评论区留下你的意见和发起。
Java是一个安详的开拓东西,它阻止开拓人员犯许多初级的错误,而大部份的错误都是基于内存打点方面的。假如你想搞粉碎,可以利用Unsafe这个类。这个类是属于sun.* API中的类,而且它不是J2SE中真正的一部份,因此你大概找不到任何的官方文档,更可悲的是,它也没有较量好的代码文档。
实例化sun.misc.Unsafe
假如你实验建设Unsafe类的实例,基于以下两种原因是不被答允的。
1)、Unsafe类的结构函数是私有的;
2)、固然它有静态的getUnsafe()要领,可是假如你实验挪用Unsafe.getUnsafe(),会获得一个SecutiryException。这个类只有被JDK信任的类实例化。
可是这总会是有变通的办理步伐的,一个简朴的方法就是利用反射举办实例化:
Field f = Unsafe.class.getDeclaredField("theUnsafe"); //Internal reference f.setAccessible(true); Unsafe unsafe = (Unsafe) f.get(null);
注:IDE如Eclipse对会这样的利用报错,不外不消担忧,直接运行代码就行,可以正常运行的。
(译者注:尚有一种办理方案,就是将Eclipse中这种限制获取由错误,修改为告诫,详细操纵为将 Windows->Preference…->Java->Compiler->Errors/Warnings中的"Deprecated and restricted API",级别由Error修改为Warning就可以了)
此刻进入主题,利用这个工具我们可以做如下“有趣的”工作。
利用sun.misc.Unsafe
1)、打破限制建设实例
通过allocateInstance()要领,你可以建设一个类的实例,可是却不需要挪用它的结构函数、初使化代码、各类JVM安详查抄以及其它的一些底层的对象。纵然结构函数是私有,我们也可以通过这个要领建设它的实例。
(这个对单例模式情有独钟的措施员来说将会是一个恶梦,它们没有步伐阻止这种方法挪用)
看下面一个实例(注:为了共同这个主题,译者将原实例中的public结构函数修改为了私有的):
public class UnsafeDemo { public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, InstantiationException { Field f = Unsafe.class.getDeclaredField("theUnsafe"); // Internal reference f.setAccessible(true); Unsafe unsafe = (Unsafe) f.get(null); // This creates an instance of player class without any initialization Player p = (Player) unsafe.allocateInstance(Player.class); System.out.println(p.getAge()); // Print 0 p.setAge(45); // Let's now set age 45 to un-initialized object System.out.println(p.getAge()); // Print 45 } } class Player { private int age = 12; private Player() { this.age = 50; } public int getAge() { return this.age; } public void setAge(int age) { this.age = age; } }
2)、利用直接获取内存的方法实现浅克隆
如何实现浅克隆?在clone(){…}要领中挪用super.clone(),对吗?这里存在的问题是首先你必需继承Cloneable接口,而且在所有你需要做浅克隆的工具中实现clone()要领,对付一个懒懒的措施员来说,这个事情量太大了。
我不推荐上面的做法而是直接利用Unsafe,我们可以仅利用几行代码就实现浅克隆,而且它可以像某些东西类一样用于任意类的克隆。
这个戏法就是把一个工具的字节码拷贝到内存的别的一个处所,然后再将这个工具转换为被克隆的工具范例。
#p#副标题#e#
3)、来自黑客的暗码安详
这个恰似很有趣吧?实事就是这样的。开拓人员建设暗码可能是担保暗码到字符串中,然后在应用措施的代码中利用这些暗码,利用事后,智慧的措施员会把字符串的引用设为NULL,因此它就不会被引用着而且很容易被垃圾收集器给接纳掉。
可是从你将引用设为NULL到被垃圾收集器收集的这个时间段之内(原文:But from the time, you made the reference null to the time garbage collector kicks in),它是处于字符串池中的,而且在你系统中举办一个巨大的进攻(原文:And a sophisticated attack on your system),也是可以读取到你的内存区域而且得到暗码,固然时机很小,可是老是存在的。
这就是为什么发起利用char[]数组存放暗码,当利用完事后,你可以迭代处理惩罚当前数组,修改/清空这些字符。
#p#分页标题#e#
别的一个方法就是利用把戏类Unsafe。你可以建设别的一个和当前暗码字符串具有沟通长度的姑且字符串,将姑且暗码中的每个字符都设值为"?"可能"*"(任何字符都可以),当你完成暗码的逻辑后,你只需要简朴的将姑且暗码中的字节数组拷贝到原始的暗码串中,这就是利用姑且暗码包围真实的暗码。
示例代码大概会是这样:
String password = new String("[email protected]$e"); String fake = new String(password.replaceAll(".", "?")); System.out.println(password); // [email protected]$e System.out.println(fake); // ???????????? getUnsafe().copyMemory(fake, 0L, null, toAddress(password), sizeOf(password)); System.out.println(password); // ???????????? System.out.println(fake); // ????????????
运行时动态建设类
我们可以在运行时运态的建设类,譬喻通过编译后的.class文件,操纵方法就是将.class文件读取到字节数据组中,并将其传到defineClass要领中。
//Sample code to craeet classes byte[] classContents = getClassContent(); Class c = getUnsafe().defineClass(null, classContents, 0, classContents.length); c.getMethod("a").invoke(c.newInstance(), null); //Method to read .class file private static byte[] getClassContent() throws Exception { File f = new File("/home/mishadoff/tmp/A.class"); FileInputStream input = new FileInputStream(f); byte[] content = new byte[(int)f.length()]; input.read(content); input.close(); return content; }
4)、超大数组
从所周知,常量Integer.MAX_VALUE是JAVA中数组长度的最大值,假如你想建设一个很是大的数组(固然在凡是的应用中不行能会用上),可以通过对内存举办直接分派实现。
下面这个示例将会建设分派一段持续的内存(数组),它的容易是答允最大容量的两倍。
class SuperArray { private final static int BYTE = 1; private long size; private long address; public SuperArray(long size) { this.size = size; //获得分派内存的起始地点 address = getUnsafe().allocateMemory(size * BYTE); } public void set(long i, byte value) { getUnsafe().putByte(address + i * BYTE, value); } public int get(long idx) { return getUnsafe().getByte(address + idx * BYTE); } public long size() { return size; } }
应用示例
long SUPER_SIZE = (long)Integer.MAX_VALUE * 2; SuperArray array = new SuperArray(SUPER_SIZE); System.out.println("Array size:" + array.size()); // 4294967294 for (int i = 0; i < 100; i++) { array.set((long)Integer.MAX_VALUE + i, (byte)3); sum += array.get((long)Integer.MAX_VALUE + i); } System.out.println("Sum of 100 elements:" + sum); // 300
但请留意这大概会导致JVM挂掉。
竣事语
sun.misc.Unsafe provides almost unlimited capabilities for exploring and modification of VM’s runtime data structures. Despite the fact that these capabilities are almost inapplicable in Java development itself, Unsafe is a great tool for anyone who want to study HotSpot VM without C++ code debugging or need to create ad hoc profiling instruments.
sun.misc.Unsafe提供了可以随意查察及修改JVM中运行时的数据布局,尽量这些成果在JAVA开拓自己是不合用的,Unsafe是一个用于研究进修HotSpot虚拟机很是棒的东西,因为它不需要挪用C++代码,可能需要建设即时阐明的东西。
From:csdn博客 冯立彬