java unsafe魔法类

 一、简介

Unsafe类使Java拥有了像C语言的指针一样操作内存空间的能力,同时也带来了指针的问题。过度的使用Unsafe类会使得出错的几率变大,因此Java官方并不建议使用的。

二、unsafe类各方法介绍

unsafe类大部分是native方法,内容对应jdk源码中的unsafe.cpp文件,主要包含

1、系统相关

主要返回某些低级别的内存信息。如:

  • addressSize()返回系统指针大小
  • pageSize()返回内存页大小

2、对象操作

主要提供Object和它的域操纵方法,如:

  • allocateInstance(Class)创建一个对象
  • objectFieldOffset(Field)获取对象某个属性的地址偏移值

3、Class相关

主要提供Class和它的静态域操纵方法,如:

  • staticFieldOffset(Field)获取给定静态字段的内存地址偏移量
  • staticFieldBase(Field)获取一个静态类中给定字段的对象指针
  • defineClass(xxx)定义一个类,此方法会跳过JVM的所有安全检查
  • defineAnonymousClass(xxx)定义一个匿名类,默认情况下,ClassLoader(类加载器)和ProtectionDomain(保护域)实例来源于调用者
  • ensureClassInitialized(Class)检测给定的类是否已经初始化。通常在获取一个类的静态属性的时候(因为一个类如果没初始化,它的静态属性也不会初始化)使用。
  • shouldBeInitialized(Class)判断是否需要初始化一个类,通常在获取一个类的静态属性的时候(因为一个类如果没初始化,它的静态属性也不会初始化)使用。 当且仅当ensureClassInitialized方法不生效时返回false。

4、数组相关

数组操纵方法,如:

  • arrayBaseOffset(Class)返回数组中第一个元素的偏移地址
  • arrayIndexScale(Class)返回数组中一个元素占用的大小

5、Memory相关

直接内存访问方法(绕过JVM堆直接操纵本地内存),如:

  • allocateMemory(long)分配一段long长度的内存空间
  • reallocateMemory(long var1, long var3)重新给var1起始地址的内存分配长度为var3字节的内存,返回新的内存起始地址偏移量
  • setMemory(XXX)将给定内存块中的所有字节设置为固定值(通常是0)。
  • copyMemory(XXX)复制内存
  • freeMemory(long)释放内存
  • putXXX(XXX)设置给定对象的XXX值(如int值)
  • getXXX(XXX);获得给定对象的指定偏移量offset的XXX值(如int值)
  • putXXXVolatile(XXX)设置给定对象的XXX值(如int值),使用volatile语义,即设置后立马更新到内存对其他线程可见
  • getXXXVolatile(XXX);获得给定对象的指定偏移量offset的XXX值(如int值),使用volatile语义,总能获取到最新的XXX值(如int值)。
  • putOrderedInt(Object var1, long var2, int var4)(将整数写入指定内存地址、有序或者有延迟的方法)

6、cas操作

  • compareAndSwapInt(Object var1, long var2, int var4, int var5)针对Object对象进行CAS操作。比较并交换,更新成功返回true,否则返回false。
  • compareAndSwapXXX(XXX)其他类型

7、线程调度

  • park(boolean var1, long var2)线程挂起
  • unpark(Object var1)线程恢复

8、内存屏障

  • loadFence()在该方法之前的所有读操作,一定在load屏障之前执行完成。
  • storeFence()在该方法之前的所有写操作,一定在store屏障之前执行完成
  • fullFence()在该方法之前的所有读写操作,一定在full屏障之前执行完成,这个内存屏障相当于上面两个(load屏障和store屏障)的合体功能

9、多线程同步

  • monitorEnter(Object var1)锁定对象,必须通过monitorExit方法才能解锁。此方法经过实验是可以重入的,也就是可以多次调用,然后通过多次调用monitorExit进行解锁。
  • monitorExit(Object var1)解锁对象,前提是对象必须已经调用monitorEnter进行加锁,否则抛出IllegalMonitorStateException异常
  • tryMonitorEnter(Object var1)尝试锁定对象,如果加锁成功返回true,否则返回false。必须通过monitorExit方法才能解锁。

10、其他

  • getLoadAverage(double[] var1, int var2)获取系统的平均负载值
  • throwException(Throwable ee)绕过检测机制直接抛出异常

三、unsafe类java获取

通过反射

        try {
            Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
            theUnsafeField.setAccessible(true);
            Unsafe unsafe= (Unsafe) theUnsafeField.get(null);
            System.out.println(unsafe);
        } catch (Exception e) {

        }

四、unsafe应用

1、compareAndSwapInt方法的cas操作可以实现高效的无锁结构

2、分配堆外内存,绕开jvm gc管理提高性能。(直接使用java.nio.DirectByteBuffer类即可)

注意:忘记手动回收内存会产生内存泄漏。非法地址访问会导致jvm崩溃。需要分配大的连续空间、实时编程(不能容忍jvm延迟)如 java.nio常用

3、动态加载类,除了Class.forName()之外使用unsafe也能加载类。

4、创建对象时绕开构造方法。使用allocateInstance就能实现

5、内存数据修改。通过计算内存偏移量,再使用putInt方法就可直接修改字段的值

6、计算对象大小。可以通过objectFieldOffset就可以实现类似于c语言的sizeOf()函数功能,加上allocateMemory和copyMemory也能实现对象的浅复制

7、挂起、唤醒线程。park、unpark用的最多

猜你喜欢

转载自blog.csdn.net/sumengnan/article/details/125023471