sun.misc.Unsafe类 部分方法解析

sun.misc.Unsafe

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public final class Unsafe{
//Unsafe实例
private static final Unsafe theUnsafe;

//私有化构造函数
private Unsafe(){}

//获取Unsafe实例
@CallerSensitive
public static Unsafe getUnsafe(){
Class var0 = Reflection.getCallerClass();
//如果类加载器不是BootstrapClassLoader(启动类加载器)就报错
if(!VM.isSystemDomainLoader(var0.getClassLoader())){
throw new SecurityException("Unsafe");
}else{
return theUnsafe;
}
}
}
  • sun.misc.Unsafe类主要提供一些用于执行低级别、不安全操作的方法,比如直接访问系统内存资源、自主管理内存资源等。
  • Unsafe提供的方法在提升Java运行效率、增强Java语言底层资源操作能力方面起了很大作用。
  • Unsafe类使得Java拥有了像C语言指针一样操作内存的能力,增加了程序发生指针问题的风险,一定要谨慎使用。

参考《Java魔法类:Unsafe应用解析》


(〇)获取theUnsafe实例

  1. Unsafe.getUnsafe()方法可以获取theUnsafe实例,但是调用类必须要通过启动类加载器(Bootstrap ClassLoader)加载,可以通过命令行命令-Xbootclasspath/a将调用类所在的JAR包路径追加到默认的bootstrap路径中:
1
2
java -Xbootclasspath/a: ${path} 
//其中path是调用Unsafe相关方法所在类的JAR包路径
  1. 通过反射机制获取:
1
2
3
4
5
6
7
8
9
10
11
12
private static Unsafe reflectGetUnsafe(){
try{
//通过成员名称获取成员实例
Field field = Unsafe.class.getDeclaredField("theUnsafe");
//设置为可访问
field.setAccessible(true);
return (Unsafe) field.get(null);
}catch(Exception e){
LOGGER.error(e.getMessage(), e);
return null;
}
}

(一)堆外内存操作

堆外内存:堆外内存是处于JVM管控之外的内存区域(是由OS管控的系统内存),Java中对堆外内存的操作依赖于Unsafe提供的native方法。

  1. 分配堆外内存:public native long allocateMemory(long bytes);

  2. 扩充堆外内存:public native long reallocateMemory(long address, long bytes);

  3. 释放堆外内存:public native void freeMemory(long address);

  4. 在给定的内存块中设置值:public native void setMemory(Object o, long offset, long bytes, byte value);

  5. 内存拷贝public native void copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes);

  6. 获取给定地址值,忽略修饰符的访问限制:public native Object getObject(Object o, long offset);

    getObject()外还有getInt()getDouble()getLong()getChar()

  7. 为给定地址设置值,忽略修饰符的访问限制:public native void putObject(Object o, long offset, Object x);

    putObject()外还有putInt()putDouble()putLong()putChar()

  8. 获取给定地址的byte类型的值:public native byte getByte(long address);

  9. 为给定地址设置byte类型的值:public native void putByte(long address, byte x);

DirectByteBuffer堆外内存分配

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
DirectByteBuffer(int cap){
super(-1, 0, cap, cap);
boolean pa = VM.isDirectMemoryPageAligned();
int ps = Bits.pageSize();
long size = Math.max(1L, (long)cap + (pa ? ps : 0));
Bits.reserveMemory(size, cap);

long base = 0;
try{
//分配堆外内存,返回基地址
base = unsafe.allocateMemory(size);
}catch(OutOfMemoryError x){
Bits.unreserveMemory(size, cap);
throw x;
}
//内存初始化
unsafe.setMemory(base, size, (byte) 0);
if(pa && (base % ps != 0)){
address = base + ps - (base & (ps - 1));
}else{
address = base;
}
//追踪DirectByteBuffer对象的垃圾回收,
//以实现DirectByteBuffer对象被回收时,分配的堆外内存一起释放
cleaner = Cleaner.create(this, new Deallocator(base, size, cap));
att = null;
}

(二)CAS(乐观锁)

1
2
3
4
5
6
7
8
9
//o         :要修改的对象
//offset :偏移量
//expected :期望值
//update :更新值
public final native boolean compareAndSwapObject(Object o, long offset, Object expected, Object update);

public final native boolean compareAndSwapInt(Object o, long offset, int expected, int update);

public final native boolean compareAndSwapLong(Object o, long offset, long expected, long update);

底层实现即CPU指令cmpxchg


(三)线程调度

  1. 阻塞线程:public native void park(boolean isAbsolute, long time);
  2. 取消阻塞线程:public native void unpark(Object thread);
  3. 获取可重入对象锁public native void monitorEnter(Object o);
  4. 释放对象锁public native void monitorExit(Object o);
  5. 尝试获取对象锁:public native boolean tryMonitorEnter(Object o);
-------------本文结束感谢您的阅读-------------

本文标题:sun.misc.Unsafe类 部分方法解析

文章作者:DragonBaby308

发布时间:2019年10月31日 - 00:09

最后更新:2019年10月31日 - 00:09

原始链接:http://www.dragonbaby308.com/sun-misc-Unsafe/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

急事可以使用右下角的DaoVoice,我绑定了微信会立即回复,否则还是推荐Valine留言喔( ఠൠఠ )ノ
0%