【JAVA筆記——道】JAVA記憶體操作 sun.misc.Unsafe類
阿新 • • 發佈:2019-02-19
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);
Unsafe做操作的是直接記憶體區,所以該類沒有辦法通過HotSpot的GC進行回收,需要進行手動回收,因此在使用此類時需要注意記憶體洩漏(Memory Leak)和記憶體溢位(Out Of Memory)