Jdk之Unsafe總結
因為Netty裡面用到了Unsafe物件,所以就回過頭來看了一下
前言
Java 不能直接訪問作業系統底層,而是通過本地方法來訪問。Unsafe 類提供了硬體級別的原子操作。
Unsafe 類在 sun.misc 包下,不屬於 Java 標準。很多 Java 的基礎類庫,包括一些被廣泛使用的高效能開發庫都是基於 Unsafe 類開發,比如 Netty 等。
Unsafe 是用於在實質上擴充套件 Java 語言表達能力、便於在更高層(Java 層)程式碼裡實現原本要在更低層(C 層)實現的核心庫功能用的。
這些功能包括裸記憶體的申請/釋放/訪問,低層硬體的 atomic/volatile 支援,建立未初始化物件等。
它原本的設計就只應該被標準庫使用,因此不建議在生產環境中使用。
Unsafe 物件不能直接通過 new Unsafe() 或呼叫 Unsafe.getUnsafe() 獲取。
Unsafe 被設計成單例模式,構造方法私有。
getUnsafe 被設計成只能從引導類載入器(bootstrap class loader)載入。
那麼我們怎麼來獲取呢?
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);
常用方法
Class 相關
主要提供 Class 和它的靜態欄位的操作方法。
/靜態屬性的偏移量,用於在對應的 Class 物件中讀寫靜態屬性
public native long staticFieldOffset(Field f);
public native Object staticFieldBase(Field f);
//判斷是否需要初始化一個類
public native boolean shouldBeInitialized(Class c);
//確保類被初始化
public native void ensureClassInitialized(Class c);
//定義一個類,可用於動態建立類
public native Class defineClass(String name, byte[] b, int off, int len, ClassLoader loader, ProtectionDomain protectionDomain);
//動態建立類
public native Class defineClass(String var1, byte[] var2, int var3, int var4);
//定義一個匿名類,可用於動態建立類
public native Class defineAnonymousClass(Class hostClass, byte[] data, Object[] cpPatches);
Object 相關
Java 中的基本型別(boolean、byte、char、short、int、long、float、double)及物件引用型別都有以下方法。
//獲得物件的欄位偏移量
public native long objectFieldOffset(Field f);
//獲得給定物件地址偏移量的int值
public native int getInt(Object o, long offset);
//設定給定物件地址偏移量的int值
public native void putInt(Object o, long offset, int x);
//獲得給定物件地址偏移量的值
public native Object getObject(Object o, long offset);
//設定給定物件地址偏移量的值
public native void putObject(Object o, long offset, Object x);
//建立物件,但並不會呼叫其構造方法。如果類未被初始化,將初始化類。
public native Object allocateInstance(Class cls) throws InstantiationException;
陣列相關
通過 arrayBaseOffset 和 arrayIndexScale 可定位陣列中每個元素在記憶體中的位置。
//返回陣列中第一個元素的偏移地址
public native int arrayBaseOffset(Class arrayClass);
//boolean、byte、short、char、int、long、float、double,及物件型別均有以下方法
/** The value of {@code arrayBaseOffset(boolean[].class)} */
public static final int ARRAY_BOOLEAN_BASE_OFFSET = theUnsafe.arrayBaseOffset(boolean[].class);
/**
* Report the scale factor for addressing elements in the storage
* allocation of a given array class. However, arrays of "narrow" types
* will generally not work properly with accessors like {@link
* #getByte(Object, int)}, so the scale factor for such classes is reported
* as zero.
*
* @see #arrayBaseOffset
* @see #getInt(Object, long)
* @see #putInt(Object, long, int)
*/
//返回陣列中每一個元素佔用的大小
public native int arrayIndexScale(Class arrayClass);
//boolean、byte、short、char、int、long、float、double,及物件型別均有以下方法
/** The value of {@code arrayIndexScale(boolean[].class)} */
public static final int ARRAY_BOOLEAN_INDEX_SCALE = theUnsafe.arrayIndexScale(boolean[].class);
CAS 相關
compareAndSwap,記憶體偏移地址 offset,預期值 expected,新值 x。如果變數在當前時刻的值和預期值 expected 相等,嘗試將變數的值更新為 x。如果更新成功,返回 true;否則,返回 false。
//更新變數值為x,如果當前值為expected
//o:物件 offset:偏移量 expected:期望值 x:新值
public final native boolean compareAndSwapObject(Object o, long offset, Object expected, Object x);
public final native boolean compareAndSwapInt(Object o, long offset, int expected, int x);
public final native boolean compareAndSwapLong(Object o, long offset, long expected, long x);
執行緒排程相關
主要包括監視器鎖定、解鎖等。
//取消阻塞執行緒
public native void unpark(Object thread);
//阻塞執行緒
public native void park(boolean isAbsolute, long time);
//獲得物件鎖
public native void monitorEnter(Object o);
//釋放物件鎖
public native void monitorExit(Object o);
//嘗試獲取物件鎖,返回 true 或 false 表示是否獲取成功
public native boolean tryMonitorEnter(Object o);
volatile 相關讀寫
//從物件的指定偏移量處獲取變數的引用,使用 volatile 的載入語義
//相當於 getObject(Object, long) 的 volatile 版本
//從主存中獲取值
public native Object getObjectVolatile(Object o, long offset);
//儲存變數的引用到物件的指定的偏移量處,使用 volatile 的儲存語義
//相當於 putObject(Object, long, Object) 的 volatile 版本
//設定值重新整理主存
public native void putObjectVolatile(Object o, long offset, Object x);
/**
* Version of {@link #putObjectVolatile(Object, long, Object)}
* that does not guarantee immediate visibility of the store to
* other threads. This method is generally only useful if the
* underlying field is a Java volatile (or if an array cell, one
* that is otherwise only accessed using volatile accesses).
*/
public native void putOrderedObject(Object o, long offset, Object x);
/** Ordered/Lazy version of {@link #putIntVolatile(Object, long, int)} */
public native void putOrderedInt(Object o, long offset, int x);
/** Ordered/Lazy version of {@link #putLongVolatile(Object, long, long)} */
public native void putOrderedLong(Object o, long offset, long x);
記憶體屏障相關
JDK 1.8 引入 ,用於定義記憶體屏障,避免程式碼重排序。
//記憶體屏障,禁止 load 操作重排序,即屏障前的load操作不能被重排序到屏障後,屏障後的 load 操作不能被重排序到屏障前
public native void loadFence();
//記憶體屏障,禁止 store 操作重排序,即屏障前的 store 操作不能被重排序到屏障後,屏障後的 store 操作不能被重排序到屏障前
public native void storeFence();
//記憶體屏障,禁止 load、store 操作重排序
public native void fullFence();
記憶體管理(非堆記憶體)
allocateMemory 所分配的記憶體需要手動 free(不被 GC 回收)
//(boolean、byte、char、short、int、long、float、double) 都有以下 get、put 兩個方法。
//獲得給定地址上的 int 值
public native int getInt(long address);
//設定給定地址上的 int 值
public native void putInt(long address, int x);
//獲得本地指標
public native long getAddress(long address);
//儲存本地指標到給定的記憶體地址
public native void putAddress(long address, long x);
//分配記憶體
public native long allocateMemory(long bytes);
//重新分配記憶體
public native long reallocateMemory(long address, long bytes);
//初始化記憶體內容
public native void setMemory(Object o, long offset, long bytes, byte value);
//初始化記憶體內容
public void setMemory(long address, long bytes, byte value) {
setMemory(null, address, bytes, value);
}
//記憶體內容拷貝
public native void copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes);
//記憶體內容拷貝
public void copyMemory(long srcAddress, long destAddress, long bytes) {
copyMemory(null, srcAddress, null, destAddress, bytes);
}
//釋放記憶體
public native void freeMemory(long address);
系統相關
//返回指標的大小。返回值為 4 或 8。
public native int addressSize();
/** The value of {@code addressSize()} */
public static final int ADDRESS_SIZE = theUnsafe.addressSize();
//記憶體頁的大小。
public native int pageSize();
其它
//獲取系統的平均負載值,loadavg 這個 double 陣列將會存放負載值的結果,nelems 決定樣本數量,nelems 只能取值為 1 到 3,分別代表最近 1、5、15 分鐘內系統的平均負載。
//如果無法獲取系統的負載,此方法返回 -1,否則返回獲取到的樣本數量(loadavg 中有效的元素個數)。
public native int getLoadAverage(double[] loadavg, int nelems);
//繞過檢測機制直接丟擲異常。
public native void throwException(Throwable ee);
相關文章
- 總結:JDK1.5-JDK1.8各個新特性JDK
- Java安全之Unsafe類Java
- JDK1.8新特性總結JDK
- 通俗易懂,JDK 併發容器總結JDK
- JDK8 String類知識總結JDK
- JDK8新特性學習總結JDK
- 【Java】jdk1.8新特性及用法總結JavaJDK
- JDK 1.5 - 1.8 各版本的新特性總結JDK
- 死磕 java魔法類之Unsafe解析Java
- Unsafe
- Netty 原始碼剖析之 unSafe.read 方法Netty原始碼
- JUC整理筆記一之細說Unsafe筆記
- Java雙刃劍之Unsafe類詳解Java
- JS 總結之物件JS物件
- JS 總結之 classJS
- Java中的Unsafe在安全領域的一些應用總結和復現Java
- Oracle之Hint使用總結Oracle
- Android之SpannableString、SpannableStringBuilder總結AndroidUI
- Linux 命令總結之 topLinux
- Unsafe原子性
- __unsafe_unretainedAI
- Go unsafe包Go
- 深入學習之連結與總結
- (2)caffe總結之目錄結構
- PHP 學習總結之字串PHP字串
- Java集合(5)之 List 總結Java
- CTF之做題總結(六)
- selenium之xpath語法總結
- 《演算法之美》總結演算法
- 微機原理之DMA總結
- 跟我一起剖析 Java 併發原始碼之 UnsafeJava原始碼
- Java中的UnsafeJava
- Java 的 Unsafe 類Java
- Go unsafe 包探究Go
- 詳解Unsafe類
- 走進 JDK 之 IntegerJDK
- 走進 JDK 之 BooleanJDKBoolean
- 走進 JDK 之 StringJDK