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();
}
}