Unsafe
1.介绍
Unsafe是位于sun.misc包下的一个类,主要提供一些用于执行低级别、不安全的底层操作,如直接访问系统内存资源、自主管理内存资源等,Unsafe大量的方法都是native方法,基于C++语言实现,这些方法在提升Java运行效率、增强Java语言底层资源操作能力方面起到了很大的作用
从名字中我们可以看出来这个类对普通程序员来说是“危险”的,一般的应用开发都不会涉及到此类,Java官方也不建议直接在应用程序中使用
Unsafe的功能如下图所示:
从JDK9开始,会尽可能使用VarHandle代替Unsafe,实际上VarHandle内部有几个内存屏障相关的方法还是基于Unsafe。可以说,Unsafe是更底层的API,建议使用VarHandle而不是Unsafe
2.使用建议
- Unsafe有可能在未来的JDK版本移除或者不允许Java应用代码使用,这一点可能导致使用了Unsafe的应用无法运行在高版本的JDK。
- Unsafe的不少方法中必须提供原始地址(内存地址)和被替换对象的地址,偏移量要自己算,一旦出现问题就是JVM崩溃级别的异常,会导致整个JVM实例崩溃,表现为应用程序突然挂
- Unsafe提供的直接内存访问的方法中使用的内存不受JVM管理(无法GC),需要手动管理,一旦出现疏忽很有可能成为内存泄漏的源头
3.使用场景
- 高性能需求:通过直接操作内存和对象,可以避免许多不必要的检查和开销,从而提升性能,这在高性能库中尤为重要
- 底层实现:一些底层的JVM功能或库(如直接内存访问,CAS操作)需要使用Unsafe来实现
4.创建Unsafe对象
问题
Unsafe是饿汉单例模式的,在使用getUnsafe去获取Unsafe对象会判断类加载器是不是BootStrap加载器不是就抛出异常,可见Unsafe这个类是不希望被使用的,如果要获取他有两种方式第一种就是使用BootStrap加载器第二种就是通过反射
源码
private Unsafe() {
}
static {
registerNatives();
Reflection.registerMethodsToFilter(Unsafe.class, new String[]{"getUnsafe"});
theUnsafe = new Unsafe();
ARRAY_BOOLEAN_BASE_OFFSET = theUnsafe.arrayBaseOffset(boolean[].class);
ARRAY_BYTE_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class);
ARRAY_SHORT_BASE_OFFSET = theUnsafe.arrayBaseOffset(short[].class);
ARRAY_CHAR_BASE_OFFSET = theUnsafe.arrayBaseOffset(char[].class);
ARRAY_INT_BASE_OFFSET = theUnsafe.arrayBaseOffset(int[].class);
ARRAY_LONG_BASE_OFFSET = theUnsafe.arrayBaseOffset(long[].class);
ARRAY_FLOAT_BASE_OFFSET = theUnsafe.arrayBaseOffset(float[].class);
ARRAY_DOUBLE_BASE_OFFSET = theUnsafe.arrayBaseOffset(double[].class);
ARRAY_OBJECT_BASE_OFFSET = theUnsafe.arrayBaseOffset(Object[].class);
ARRAY_BOOLEAN_INDEX_SCALE = theUnsafe.arrayIndexScale(boolean[].class);
ARRAY_BYTE_INDEX_SCALE = theUnsafe.arrayIndexScale(byte[].class);
ARRAY_SHORT_INDEX_SCALE = theUnsafe.arrayIndexScale(short[].class);
ARRAY_CHAR_INDEX_SCALE = theUnsafe.arrayIndexScale(char[].class);
ARRAY_INT_INDEX_SCALE = theUnsafe.arrayIndexScale(int[].class);
ARRAY_LONG_INDEX_SCALE = theUnsafe.arrayIndexScale(long[].class);
ARRAY_FLOAT_INDEX_SCALE = theUnsafe.arrayIndexScale(float[].class);
ARRAY_DOUBLE_INDEX_SCALE = theUnsafe.arrayIndexScale(double[].class);
ARRAY_OBJECT_INDEX_SCALE = theUnsafe.arrayIndexScale(Object[].class);
ADDRESS_SIZE = theUnsafe.addressSize();
}
@CallerSensitive
public static Unsafe getUnsafe() {
Class var0 = Reflection.getCallerClass();
if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
throw new SecurityException("Unsafe");
} else {
return theUnsafe;
}
}
反射获取Unsafe对象
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);
public class JvmUtil {
public static Unsafe getUnsafe{
try{
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
return (Unsafe) theUnsafe.get(null);
}catch(Exception e){
e.printStackTrace();
}
}
}