Java Unsafe
Unsafe是位于sun.misc包下的一个类,主要提供一些用于执行低级别、不安全操作的方法,如直接访问系统内存资源、自主管理内存资源等,这些方法在提升Java运行效率、增强Java语言底层资源操作能力方面起到了很大的作用。但由于Unsafe类使Java语言拥有了类似C语言指针一样操作内存空间的能力,这无疑也增加了程序发生相关指针问题的风险。在程序中过度、不正确使用Unsafe类会使得程序出错的概率变大,使得Java这种安全的语言变得不再“安全”,因此对Unsafe的使用一定要慎重。
Unsafe类为一单例实现,提供静态方法getUnsafe
获取Unsafe
实例,当且仅当调用getUnsafe
方法的类为引导类加载器所加载时才合法,否则抛出SecurityException异常。
如何获取Unsafe实例?
1、从getUnsafe方法的使用限制条件出发,通过Java命令行命令-Xbootclasspath/a把调用Unsafe相关方法的类A所在jar包路径追加到默认的bootstrap路径中,使得A被引导类加载器加载,从而通过Unsafe.getUnsafe方法安全的获取Unsafe实例。
2、通过反射获取单例对象theUnsafe。
Unsafe功能介绍
Unsafe提供的API大致可分为内存操作、CAS、Class相关、对象操作、线程调度、系统 信息获取、内存屏障、数组操作等几类,下面将对其相关方法和应用场景进行详细介绍。
通常,在Java中创建的对象都处于堆内内存(heap)中,堆内内存是由JVM所管控的Java进程内存,并且它们遵循JVM的内存管理机制,JVM会采用垃圾回收机制统一管理堆内存。与之相对的是堆外内存,存在于JVM管控之外的内存区域,Java中对堆外内存的操作,依赖于Unsafe
提供的操作堆外内存的native
方法。
使用堆外内存的原因
- 对垃圾回收停顿的改善。由于堆外内存是直接受操作系统管理而不是JVM,所以 当使用堆外内存时,即可保持较小的堆内内存规模。从而在GC时减少回收停顿对于应用的影响。
- 提升程序I/O操作的性能。通常在I/O通信过程中,会存在堆内内存到堆外内存的 数据拷贝操作,对于需要频繁进行内存间数据拷贝且生命周期较短的暂存数据,都建议存储到堆外内存。
典型应用
DirectByteBuffer
是Java用于实现堆外内存的一个重要类,通常用在通信过程中做缓冲池,如在Netty、MINA等NIO框架中应用广泛。DirectByteBuffer
对于堆外内存的创建、使用、销毁等逻辑均由Unsafe
提供的堆外内存API来实现。
下图为DirectByteBuffer
构造函数,创建DirectByteBuffer
的时候,通过Unsafe.allocateMemory
分配内存、Unsafe.setMemory
进行内存初始化,而后构建Cleaner对象用于跟踪DirectByteBuffer
对象的垃圾回收,以实现当DirectByteBuffer
被垃 圾回收时,分配的堆外内存一起被释放。