Unsafe 类在 sun.misc 包下,不属于Java标准。但是很多 Java 的基础类库,以及优秀的三方库都会用这个提升性能。
Unsafe 使用了单例模式,想使用 Unsafe 类就需要获取实例。由于安全限制,不能用一般的方法获取这个实例,通常都是使用反射获取
1 | public class UnsafeDemo { |
Unsafe 类几类功能:
内存管理
1 | long allocateMemory(long bytes) |
向操作系统申请一块本地内存,大小为 bytes 字节,返回内存块的地址。本地内存是指不由 JVM 管理的内存,不会被 GC 管理。底层使用 malloc 实现
1 | long reallocateMemory(long address, long bytes) |
resize 一块本地内存,address 是原内存地址, bytes 是新大小。如果 address 是 0,则内部用 allocateMemory 分配新内存;如果 bytes 是 0,则用 freeMemory 释放原内存。底层使用 realloc 实现。
1 | void freeMemory(long address) |
释放由 allocateMemory 申请的内存,底层用 free 实现
1 | int pageSize() |
返回一页内存的大小
1 | int addressSize() |
返回一个指针的大小
内存操作
内存操作需要提供地址。UnSafe 需要地址的场合会需要两个参数 Object o, long offset
- 如果 o 是 null, offset 将被视为具体的内存地址
- 如果 o 非 null,offset 被为字段在对象或数组中的偏移。 o 和 offset 一起得到一个有效地址
1 | void setMemory(Object o, long offset, long bytes, byte value) |
将一块内存设置为固定值
1 | void setMemory(long address, long bytes, byte value) |
等价于 setMemory(null, address, bytes, value);
1 | void copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes) |
复制内存
1 | void copyMemory(long srcAddress, long destAddress, long bytes) |
等价于 copyMemory(null, srcAddress, null, destAddress, bytes)
1 | T getT(Object o, long offset) |
获取/设置一块内存的值,T 可以是 int、boolean、byte、short、char、long、float、double。
1 | Object getObject(Object o, long offset) |
不需要 Object o 参数的版本,等价于 getT(null, address)
1 | T getTVolatile(Object o, long offset) |
带 volatile 语义的 put / get
1 | long getAddress(Object o, long offset) |
从指定地址获取一个内存指针
1 | void putAddress(Object o, long offset, long x) |
将指针存到指定地址
1 | void putOrderedObject(Object o, long offset, Object x) |
保证写后立即可见
计算类字段的内存偏移位置
1 | long staticFieldOffset(Field f) |
返回一个静态字段的内存位置
1 | long objectFieldOffset(Field f) |
返回一个指定字段的存储位置
1 | Object staticFieldBase(Field f) |
返回一个静态字段的存储位置,是一个引用
非常规的对象实例化
1 | Object allocateInstance(Class<?> cls) |
创建一个类实例,但不执行构造方法
数组操作
1 | int arrayBaseOffset(Class<?> arrayClass) |
返回 arrayClass 类型数组的第 0 个元素到数组对象内存开始的偏移
1 | int arrayIndexScale(Class<?> arrayClass) |
返回一个数组元素需要的长度大小
用法如下:
1 | int base = U.arrayBaseOffset(Integer[].class); |
异常
1 | void throwException(Throwable e) |
该方法抛出受检异常,但代码不必捕捉或重新抛出它,正如运行时异常一样
动态类
1 | Class<?> defineClass(String name, byte[] b, int off, int len, ClassLoader loader, ProtectionDomain protectionDomain) |
从字节码创建一个类
1 | Class<?> defineAnonymousClass(Class<?> hostClass, byte[] data, Object[] cpPatches) |
从字节码创建匿名类
1 | void ensureClassInitialized(Class<?> c) |
加载类
1 | boolean shouldBeInitialized(Class<?> c) |
检查类是否已加载
多线程同步
1 | void monitorEnter(Object obj) |
锁定对象
1 | void monitorExit(Object obj) |
释放锁
monitorEnter 和 monitorExit 的组合相当于 synchronized 关键字
1 | boolean tryMonitorEnter(Object obj) |
尝试锁定对象
以上 3 个都是 @Deprecated 的方法
原子操作
1 | boolean compareAndSwapObject(Object o, long offset, Object expected, Object x) |
如果变量的值是 expected,则更新成 x,原子更新
1 | int getAndAddInt(Object o, long offset, int delta) |
原子加
1 | getAndSetInt(Object o, long offset, int newValue) |
原子地设置新值和返回旧值
挂起与恢复
1 | void park(boolean isAbsolute, long time) |
暂停当前线程
1 | void unpark(Object thread) |
通知线程恢复
JDK concurrent 包的锁大部分用这个实现
内存屏障
1 | void loadFence() |
在该方法之前的所有读操作,一定在load屏障之前执行完成
1 | void storeFence() |
在该方法之前的所有写操作,一定在store屏障之前执行完成
1 | void fullFence() |
在该方法之前的所有读写操作,一定在 full 屏障之前执行完成,这个内存屏障相当于上面两个的合体功能