【JAVA笔记——道】JAVA内存操作 sun.misc.Unsafe类

TIP:这是一个很危险的类,不熟悉情况下别用于生产环境

如果大家熟悉java concurrent,相信对Unsafe类不陌生。

我们知道JAVA作为高级语言的重要创新一点就是在于JVM的内存管理功能,这完全区别于C语言开发过程中需要对变量的内存分配小心控制,JVM很大程度解放了码农对于内存的调整。一直以来,JAVA在大多数人心目中没有办法对内存进行操作的,其实不然,Unsafe类就是一把操作JAVA内存的钥匙。

//不可以直接被初始化
private Unsafe() {}

//可以通过get获得实例
public static Unsafe getUnsafe() {
         Class<?> caller = Reflection.getCallerClass();
          if (!VM.isSystemDomainLoader(caller.getClassLoader()))
             throw new SecurityException("Unsafe");
         return theUnsafe;
     }

在这里需要注意isSystemDomainLoader,若不设置为static final将会导致SecurityException异常

这里简单介绍几个方法:

1 类值域初始化
推荐先看一下Class初始化理解
一般类实例化的方式主要有:1.new;2.Reflect;3.ClassLoader,不同方式对应不同初始化方式

    //Unsafe提供获取实例地址
    public native Object allocateInstance(Class<?> cls)
        throws InstantiationException;
    //直接根据内存地址获取byte,Unsafe还提供了Int,Long等基本类型
    //的线程安全及非线程安全取值
    public native byte  getByte(long address);

    //同样提供了对内存数据的直接修改,并提供基本类型的线程安全及非安全
    //赋值
    public native void  putByte(long address,byte x);

2 克隆
克隆之前经常用到两种方式:1.浅度克隆;2.深度克隆
浅度克隆实现的主要方式是clonable接口的clone方法以及通过反射获取clone对象。
深度克隆一般就比较麻烦了,需要自定义深度克隆方法。
现在我们可以操控内存,不论深度克隆亦或者浅度克隆,都只是对内存对象的操作,通过内存控制,我们很容易实现对象克隆。

//熟悉的内存分配
public native long allocateMemory(long bytes);
//熟悉的内存释放
public native void freeMemory(long address);
//内存复制,C的感觉回来了吧,浅度克隆一句搞定
//深度克隆需要考虑克隆程度,因此推荐使用WakeObject,利用反射进行克隆
public void copyMemory(long srcAddress, long destAddress, long bytes) {
560         copyMemory(null, srcAddress, null, destAddress, bytes);
561     }

3.懒加载
经常并发的数据结构中低级别的优化。

//常并发控制中,简称CAS(Compare And Swap),意思是如果valueOffset
//位置包含的值与expect值相同,则更新valueOffset位置的值为update,
//并返回true,否则不更新,返回false
public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x);

//懒加载
public native void putOrderedInt(Object o, long offset, int x);

推荐看一下这篇,写的真心太好,觉得不需要再赘述JUC中Atomic class之lazySet的一点疑惑

Unsafe做操作的是直接内存区,所以该类没有办法通过HotSpot的GC进行回收,需要进行手动回收,因此在使用此类时需要注意内存泄漏(Memory Leak)和内存溢出(Out Of Memory)

原文地址:https://www.cnblogs.com/cunchen/p/9464170.html