Unsafe 基本使用

Unsafe基本使用


1 實例化Unsafe 對象

Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
return (Unsafe) theUnsafe.get(null);


分配內存,釋放內存

public native long allocateMemory(long l);
public native long reallocateMemory(long l, long l1);
public native void setMemory(long l, long l1, byte b);

3 定位內存位置

public native long staticFieldOffset(java.lang.reflect.Field field);
public native long objectFieldOffset(java.lang.reflect.Field field);
public native int arrayBaseOffset(java.lang.Class aClass);
public native int arrayIndexScale(java.lang.Class aClass);


CAS操作

    public final native boolean compareAndSwapObject(java.lang.Object o, long l, java.lang.Object o1, java.lang.Object o2);
    public final native boolean compareAndSwapInt(java.lang.Object o, long l, int i, int i1);
    public final native boolean compareAndSwapLong(java.lang.Object o, long l, long l1, long l2);

掛起與恢復

    public native void unpark(java.lang.Object o);
    public native void park(boolean b, long l);

Unsafe 類的其他用處

1)不受限地創建類的對象
調用allocateInstance方法,可繞過構造方法直接創建對象,這意味着不用對對象做任何初始化操作。

2)實現克隆
不用再實現  super.clone()  完成克隆,通過 Unsafe 實現克隆更加方便。
Unsafe 實現克隆的原理是:創建一塊新內存,將帶克隆對象的內存數據,直接拷貝到新內存中,然後對新內存做類型轉換(typecast)即可。

3)密碼銷燬
考慮這樣一種情況:
應用程序中用 String 保存密碼,用完之後,將該 String 賦值爲 null,等待垃圾回收器將其銷燬。
存在的一個問題是:在賦值爲null 到 garbage collector 參與回收期間,這個 String 存放於 String pool 中。經驗豐富的黑客可讀取該String的內存塊值以竊取密碼,雖然這種機率很低,但風險依然存在。

兩種替換方案:
(1)使用char[] 保存密碼。使用完後,可通過迭代 char[],將每一個數組元素賦值爲空。
(2)使用Unsafe。使用Unsafe的原理是:用一個 temp String 保存和密碼相同長度的任意字符串,如?,待密碼字符串使用完,將 temp String 值通過Unsafe提供的 copyMemory 方法拷貝到密碼字符串中。以此達到密碼內存擦除效果。

String password = new String("l00k@myHor$e");
String fake = new String(password.replaceAll(".","?"));
System.out.println(password);// l00k@myHor$e
System.out.println(fake);// ????????????
  
getUnsafe().copyMemory(fake, 0L, null, toAddress(password), sizeOf(password));
  
System.out.println(password);// ????????????
System.out.println(fake);// ????????????
 

4)運行時動態創建類
運行時以流的方式讀取 class 文件,然後通過Unsafe提供的defineClass方法,動態生成 Class 對象,再通過 newInstance 方法,生成對象。

byte[] classContents = getClassContent();
Class c = getUnsafe().defineClass(null, classContents, 0, classContents.length);
c.getMethod("a").invoke(c.newInstance(),null);
  
//Method to read .class file
private static byte[] getClassContent() throws Exception {
    File f = new File("/home/mishadoff/tmp/A.class");
    FileInputStream input = new FileInputStream(f);
    byte[] content = new byte[(int)f.length()];
    input.read(content);
    input.close();
    return content;
}


5)創建超大數組
能創建的java數組長度是 Integer.MAX_VALUE = 2147483647 [0x7fffffff],這是因爲數組長度只接收 int 型數據(實際能創建的最大數組長度,可能還受限於虛擬機的設置)。
使用 Unsafe 的 allocateMemory 方法,可繞過此限制:創建長度大於  Integer.MAX_VALUE 的數組(儘管在應用程序中很少使用),這是因爲 allocateMemory 方法直接向底層申請指定大小內存,而不用經過虛擬機的檢查。allocateMemory 返回創建數組的起始地址;分配的數組的值,沒有被初始化,所以不確定。

 

Unsafe 提供的強大功能,使得可以在運行時改變jvm的數據結構。
對於大多數java開發者來說,Unsafe提供的衆多底層操作功能,他們很少會用到,但對那些想學習HotSpot VM,但苦於沒有可調試的c/c++代碼的人來說,Unsafe也許是一個非常棒的工具。





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章