0.Unsafe类概述
Unsafe类存在于sun.misc.Unsafe
,网上说这个类半天使半魔鬼,并且使用的时候虽然能再很大程度上提高效率。但是很有可能导致程序发生崩溃。Unsafe类为java提供了非常强大的提高运行效率能力和与底层进行交互的能力。Unsafe类中通过其八十多个native方法及内部对于这些native方法组合使用生成的方法,提供了对于内存
、对象
、CAS
、线程
等重要目标的操作能力,使得用户可以通过Unsafe类进行底层操作。
1.如何使用Unsafe类
Unsafe
类的部分代码如下:
public final class Unsafe { private static final Unsafe theUnsafe; ......省略...... private Unsafe() { } @CallerSensitive public static Unsafe getUnsafe() { Class var0 = Reflection.getCallerClass(); if (!VM.isSystemDomainLoader(var0.getClassLoader())) { throw new SecurityException("Unsafe"); } else { return theUnsafe; } } ......省略......
首先Unsafe类有final
修饰符,因此该类无法继承。并且,其默认的构造函数为private
,因此无法再外部通过new创建实例。其内部提供了一个static
修饰的getUnsafe
方法可以返回实例化的对象,但是该方法中检测了加载该类的Loader是否为系统Loader,因此我们无法直接使用ClassLoader去加载这个类。当然我们可以通过修改系统Bootstrap Classloader
的bootclasspath
来加载这个类,但更简单的方法是直接使用反射机制加载。代码如下:
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; public class TestProject { public static void main(String argvs[]) throws IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException, NoSuchMethodException { Class myUnsafe = Class.forName("sun.misc.Unsafe"); Constructor myUnsafeConstructor = myUnsafe.getDeclaredConstructor(); myUnsafeConstructor.setAccessible(true); sun.misc.Unsafe myUnsafeInstance = (sun.misc.Unsafe) myUnsafeConstructor.newInstance(); } }
2.Unsafe类的用途
Unsafe类的用户非常广泛,主要包括:
- 类的操作:类的非常规实例化、基于偏移地址获取或者设置变量的值、基于偏移地址获取或者设置数组元素的值等。
- 内存管理:内存申请、读写
- 线程同步:监视器锁定、解锁以及CAS相关、线程恢复和挂起等
这里教程中给了两个例子,一个是调用allocateInstance无视构造方法创建类实例,还有一个是直接使用DefineClass方法直接调用JVM创建类对象不过这个方法具有版本限制。
- 1.调用allocateInstance无视构造方法的检查创建类实例
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; public class TestProject { public class UnSafeTest { private UnSafeTest() { // 假设RASP在这个构造方法中插入了Hook代码,我们可以利用Unsafe来创建类实例 System.out.println("init..."); } private void Hi() { System.out.println("Hi!!!"); } } public static void main(String argvs[]) throws IllegalAccessException, InvocationTargetException, InstantiationException, ClassNotFoundException, NoSuchMethodException { Class myUnsafe = Class.forName("sun.misc.Unsafe"); Constructor myUnsafeConstructor = myUnsafe.getDeclaredConstructor(); myUnsafeConstructor.setAccessible(true); sun.misc.Unsafe myUnsafeInstance = (sun.misc.Unsafe) myUnsafeConstructor.newInstance(); UnSafeTest unSafeTest = (UnSafeTest)myUnsafeInstance.allocateInstance(UnSafeTest.class); unSafeTest.Hi(); } }