最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java基礎(chǔ)之Unsafe內(nèi)存操作不安全類詳解

 更新時間:2021年06月07日 08:53:20   作者:源碼獵人  
Java是面向?qū)ο笳Z言,在使用Java編程時,大多數(shù)情況下都不會直接操作內(nèi)存,而且Java也不提倡直接操作內(nèi)存,但是Java中到底有沒有可以直接操作內(nèi)存的工具類呢?有!Java中提供Unsafe類可以用來來直接操作內(nèi)存,文中詳細(xì)介紹了Unsafe內(nèi)存操作不安全類,需要的朋友可以參考下

簡介

Unsafe類使Java擁有了像C語言的指針一樣操作內(nèi)存空間的能力,直接操作內(nèi)存就意味著

1、不受jvm管理,也就意味著無法被GC,需要我們手動GC,稍有不慎就會出現(xiàn)內(nèi)存泄漏。

2、Unsafe的不少方法中必須提供原始地址(內(nèi)存地址)和被替換對象的地址,偏移量要自己計算,一旦出現(xiàn)問題就是JVM崩潰級別的異常,會導(dǎo)致整個JVM實例崩潰,表現(xiàn)為應(yīng)用程序直接crash掉。

3、直接操作內(nèi)存,也意味著其速度更快,在高并發(fā)的條件之下能夠很好地提高效率。

Unsafe 類

public final class Unsafe

Unsafe類是"final"的,不允許繼承。

Unsafe 屬性

private static final Unsafe theUnsafe;
public static final int INVALID_FIELD_OFFSET = -1;
public static final int ARRAY_BOOLEAN_BASE_OFFSET;
public static final int ARRAY_BYTE_BASE_OFFSET;
public static final int ARRAY_SHORT_BASE_OFFSET;
public static final int ARRAY_CHAR_BASE_OFFSET;
public static final int ARRAY_INT_BASE_OFFSET;
public static final int ARRAY_LONG_BASE_OFFSET;
public static final int ARRAY_FLOAT_BASE_OFFSET;
public static final int ARRAY_DOUBLE_BASE_OFFSET;
public static final int ARRAY_OBJECT_BASE_OFFSET;
public static final int ARRAY_BOOLEAN_INDEX_SCALE;
public static final int ARRAY_BYTE_INDEX_SCALE;
public static final int ARRAY_SHORT_INDEX_SCALE;
public static final int ARRAY_CHAR_INDEX_SCALE;
public static final int ARRAY_INT_INDEX_SCALE;
public static final int ARRAY_LONG_INDEX_SCALE;
public static final int ARRAY_FLOAT_INDEX_SCALE;
public static final int ARRAY_DOUBLE_INDEX_SCALE;
public static final int ARRAY_OBJECT_INDEX_SCALE;
public static final int ADDRESS_SIZE;

這些屬性都是在類加載時初始化,它們都是一些類型數(shù)組指針。

Unsafe 靜態(tài)加載

static {
	registerNatives();
	Reflection.registerMethodsToFilter(Unsafe.class, new String[]{"getUnsafe"});
	theUnsafe = new Unsafe();
	ARRAY_BOOLEAN_BASE_OFFSET = theUnsafe.arrayBaseOffset(boolean[].class);
	ARRAY_BYTE_BASE_OFFSET = theUnsafe.arrayBaseOffset(byte[].class);
	ARRAY_SHORT_BASE_OFFSET = theUnsafe.arrayBaseOffset(short[].class);
	ARRAY_CHAR_BASE_OFFSET = theUnsafe.arrayBaseOffset(char[].class);
	ARRAY_INT_BASE_OFFSET = theUnsafe.arrayBaseOffset(int[].class);
	ARRAY_LONG_BASE_OFFSET = theUnsafe.arrayBaseOffset(long[].class);
	ARRAY_FLOAT_BASE_OFFSET = theUnsafe.arrayBaseOffset(float[].class);
	ARRAY_DOUBLE_BASE_OFFSET = theUnsafe.arrayBaseOffset(double[].class);
	ARRAY_OBJECT_BASE_OFFSET = theUnsafe.arrayBaseOffset(Object[].class);
	ARRAY_BOOLEAN_INDEX_SCALE = theUnsafe.arrayIndexScale(boolean[].class);
	ARRAY_BYTE_INDEX_SCALE = theUnsafe.arrayIndexScale(byte[].class);
	ARRAY_SHORT_INDEX_SCALE = theUnsafe.arrayIndexScale(short[].class);
	ARRAY_CHAR_INDEX_SCALE = theUnsafe.arrayIndexScale(char[].class);
	ARRAY_INT_INDEX_SCALE = theUnsafe.arrayIndexScale(int[].class);
	ARRAY_LONG_INDEX_SCALE = theUnsafe.arrayIndexScale(long[].class);
	ARRAY_FLOAT_INDEX_SCALE = theUnsafe.arrayIndexScale(float[].class);
	ARRAY_DOUBLE_INDEX_SCALE = theUnsafe.arrayIndexScale(double[].class);
	ARRAY_OBJECT_INDEX_SCALE = theUnsafe.arrayIndexScale(Object[].class);
	ADDRESS_SIZE = theUnsafe.addressSize();
}
private static native void registerNatives();

Unsafe 構(gòu)造函數(shù)

private Unsafe() {
}

Unsafe 對象不能直接通過 new Unsafe(),它的構(gòu)造函數(shù)是私有的。

Unsafe 實例化方法

public static Unsafe getUnsafe() {
	Class var0 = Reflection.getCallerClass();
	if (!VM.isSystemDomainLoader(var0.getClassLoader())) {
		throw new SecurityException("Unsafe");
	} else {
		return theUnsafe;
	}
}

getUnsafe 只能從引導(dǎo)類加載器(bootstrap class loader)加載,非啟動類加載器直接調(diào)用 Unsafe.getUnsafe() 方法會拋出 SecurityException 異常。解決辦法:

1、可以令代碼 " 受信任 "。運行程序時,通過 JVM 參數(shù)設(shè)置 bootclasspath 選項,指定系統(tǒng)類路徑加上使用的一個 Unsafe 路徑。

java -Xbootclasspath:/usr/jdk1.7.0/jre/lib/rt.jar:. com.Test

2、通過 Java 反射機(jī)制,暴力獲取。

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

Unsafe 內(nèi)存管理

// 獲取本地指針的大小(單位是byte),通常值為4或者8。常量ADDRESS_SIZE就是調(diào)用此方法。
public native int addressSize();
// 獲取本地內(nèi)存的頁數(shù),此值為2的冪次方。
public native int pageSize();
// 分配一塊新的本地內(nèi)存,通過bytes指定內(nèi)存塊的大小(單位是byte),返回新開辟的內(nèi)存的地址。
public native long allocateMemory(long var1);
// 通過指定的內(nèi)存地址address重新調(diào)整本地內(nèi)存塊的大小,調(diào)整后的內(nèi)存塊大小通過bytes指定(單位為byte)。
public native long reallocateMemory(long var1, long var3);
// 將給定內(nèi)存塊中的所有字節(jié)設(shè)置為固定值(通常是0)
public native void setMemory(Object var1, long var2, long var4, byte var6);
// 內(nèi)存復(fù)制
public native void copyMemory(Object var1, long var2, Object var4, long var5, long var7);
// 清除內(nèi)存
public native void freeMemory(long var1);

注意:allocateMemory方法申請的內(nèi)存,將直接脫離jvm,gc將無法管理該方式申請的內(nèi)存,用完一定要手動釋放內(nèi)存,防止內(nèi)存溢出;
JDK中示例:ByteBuffer.allocateDirect(int capacity)使用DirectByteBuffer,DirectByteBuffer中就是用allocateMemory申請堆外內(nèi)存。

Unsafe 獲取偏移量

// 返回指定變量所屬類中的內(nèi)存偏移量
public native long objectFieldOffset(Field var1);
// 獲取數(shù)組中第一個元素的地址
public native int arrayBaseOffset(Class<?> var1);
// 獲取靜態(tài)變量地址偏移值
public native long staticFieldOffset(Field var1);
// 其實就是數(shù)據(jù)中元素偏移地址的增量,數(shù)組中的元素的地址是連續(xù)的
public native int arrayIndexScale(Class<?> var1);

Unsafe 檢查類初始化

// 檢測給定的類是否需要初始化。
// 當(dāng)ensureClassInitialized方法不生效的時候才返回false
public native boolean shouldBeInitialized(Class<?> c);
// 檢測給定的類是否已經(jīng)初始化。
public native void ensureClassInitialized(Class<?> c);

Unsafe 從指定位置讀取

// 從指定內(nèi)存地址處開始讀取一個byte
public native byte getByte(long var1);
// 從指定內(nèi)存地址處開始讀取一個short 
public native short getShort(long var1);
// 從指定內(nèi)存地址處開始讀取一個char 
public native char getChar(long var1);
// 從指定內(nèi)存地址處開始讀取一個int 
public native int getInt(long var1);
// 從指定內(nèi)存地址處開始讀取一個long 
public native long getLong(long var1);
// 從指定內(nèi)存地址處開始讀取一個float 
public native float getFloat(long var1);
// 從指定內(nèi)存地址處開始讀取一個double 
public native double getDouble(long var1);

Unsafe 向指定位置寫值

// 向指定位置寫入一個int 
public native void putInt(long var1, int var3);
// 向指定位置寫入一個char 
public native void putChar(long var1, char var3);
// 向指定位置寫入一個byte 
public native void putByte(long var1, byte var3);
// 向指定位置寫入一個short 
public native void putShort(long var1, short var3);
// 向指定位置寫入一個long 
public native void putLong(long var1, long var3);
// 向指定位置寫入一個float 
public native void putFloat(long var1, float var3);
// 向指定位置寫入一個double 
public native void putDouble(long var1, double var3);

Unsafe 對象操作

從指定偏移量處讀取對象屬性(非主存)

public native int getInt(Object var1, long var2);
public native Object getObject(Object var1, long var2);
public native boolean getBoolean(Object var1, long var2);
public native byte getByte(Object var1, long var2);
public native short getShort(Object var1, long var2);
public native char getChar(Object var1, long var2);
public native long getLong(Object var1, long var2);
public native float getFloat(Object var1, long var2);
public native double getDouble(Object var1, long var2);

向指定偏移量處修改對象屬性(非主存)

public native void putInt(Object var1, long var2, int var4);
public native void putObject(Object var1, long var2, Object var4);
public native void putBoolean(Object var1, long var2, boolean var4);
public native void putByte(Object var1, long var2, byte var4);
public native void putShort(Object var1, long var2, short var4);
public native void putChar(Object var1, long var2, char var4);
public native void putLong(Object var1, long var2, long var4);
public native void putFloat(Object var1, long var2, float var4);
public native void putDouble(Object var1, long var2, double var4);

向指定偏移量處修改對象屬性(主存)

public native Object getObjectVolatile(Object var1, long var2);
public native int getIntVolatile(Object var1, long var2);
public native boolean getBooleanVolatile(Object var1, long var2);
public native byte getByteVolatile(Object var1, long var2);
public native short getShortVolatile(Object var1, long var2);
public native char getCharVolatile(Object var1, long var2);
public native long getLongVolatile(Object var1, long var2);
public native float getFloatVolatile(Object var1, long var2);
public native double getDoubleVolatile(Object var1, long var2);

向指定偏移量處修改對象屬性(主存)

public native void putObjectVolatile(Object var1, long var2, Object var4);
public native void putIntVolatile(Object var1, long var2, int var4);
public native void putBooleanVolatile(Object var1, long var2, boolean var4);
public native void putByteVolatile(Object var1, long var2, byte var4);
public native void putShortVolatile(Object var1, long var2, short var4);
public native void putCharVolatile(Object var1, long var2, char var4);
public native void putLongVolatile(Object var1, long var2, long var4);
public native void putFloatVolatile(Object var1, long var2, float var4);
public native void putDoubleVolatile(Object var1, long var2, double var4);
public native void putOrderedObject(Object var1, long var2, Object var4);
public native void putOrderedObject(Object var1, long var2, Object var4);
public native void putOrderedInt(Object var1, long var2, int var4);
public native void putOrderedLong(Object var1, long var2, long var4);

Unsafe CAS操作

public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);
public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);

針對對象進(jìn)行CAS操作,本質(zhì)更新對象中指定偏移量的屬性,當(dāng)原值為var4時才會更新成var5并返回true,否則返回false。
舉例:volatile i=0;有多個線程修改i的值,A線程只有在i=1時修改為2,如果代碼如下

if (i == 1) {i = 2;} 

這樣時有問題的,if比較完i可能已經(jīng)被別人修改了,這種場景特別適合CAS,使用CAS代碼如下

boolean isUpdate =  compareAndSwapInt(object, offset, 1, 2)

相當(dāng)于讀->判斷->寫一次搞定(實在不能理解CAS,可以這么理解)

Unsafe 線程的掛起和恢復(fù)

public native void park(boolean var1, long var2);

阻塞當(dāng)前線程直到一個unpark方法出現(xiàn)(被調(diào)用)、一個用于unpark方法已經(jīng)出現(xiàn)過(在此park方法調(diào)用之前已經(jīng)調(diào)用過)、線程被中斷或者time時間到期(也就是阻塞超時)。在time非零的情況下,如果isAbsolute為true,time是相對于新紀(jì)元之后的毫秒,否則time表示納秒。這個方法執(zhí)行時也可能不合理地返回(沒有具體原因)。并發(fā)包java.util.concurrent中的框架對線程的掛起操作被封裝在LockSupport類中,LockSupport類中有各種版本pack方法,但最終都調(diào)用了Unsafe#park()方法。

public native void unpark(Object var1);

釋放被park創(chuàng)建的在一個線程上的阻塞。這個方法也可以被使用來終止一個先前調(diào)用park導(dǎo)致的阻塞。這個操作是不安全的,因此必須保證線程是存活的(thread has not been destroyed)。從Java代碼中判斷一個線程是否存活的是顯而易見的,但是從native代碼中這機(jī)會是不可能自動完成的。

Unsafe 內(nèi)存屏障

public native void loadFence();

在該方法之前的所有讀操作,一定在load屏障之前執(zhí)行完成。

public native void storeFence();

在該方法之前的所有寫操作,一定在store屏障之前執(zhí)行完成

public native void fullFence();

在該方法之前的所有讀寫操作,一定在full屏障之前執(zhí)行完成,這個內(nèi)存屏障相當(dāng)于上面兩個(load屏障和store屏障)的合體功能。

Unsafe 其他

public native int getLoadAverage(double[] loadavg, int nelems);

獲取系統(tǒng)的平均負(fù)載值,loadavg這個double數(shù)組將會存放負(fù)載值的結(jié)果,nelems決定樣本數(shù)量,nelems只能取值為1到3,分別代表最近1、5、15分鐘內(nèi)系統(tǒng)的平均負(fù)載。如果無法獲取系統(tǒng)的負(fù)載,此方法返回-1,否則返回獲取到的樣本數(shù)量(loadavg中有效的元素個數(shù))。實驗中這個方法一直返回-1,其實完全可以使用JMX中的相關(guān)方法替代此方法。

public native void throwException(Throwable ee);

繞過檢測機(jī)制直接拋出異常。

到此這篇關(guān)于Java基礎(chǔ)之Unsafe內(nèi)存操作不安全類詳解的文章就介紹到這了,更多相關(guān)Unsafe內(nèi)存操作不安全類內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java實現(xiàn)動物換位游戲完整?過程詳解

    Java實現(xiàn)動物換位游戲完整?過程詳解

    大家好,今天嘗試用Java編程設(shè)計一個GUI界面的動物換位游戲,游戲的結(jié)果是讓左右兩組的動物交換位置,以下是具體設(shè)計過程,供大家參考
    2022-07-07
  • Java?NIO緩沖區(qū)Buffer基礎(chǔ)教程示例

    Java?NIO緩沖區(qū)Buffer基礎(chǔ)教程示例

    這篇文章主要介紹了Java?NIO緩沖區(qū)Buffer基礎(chǔ)教程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • struts2如何使用攔截器進(jìn)行用戶權(quán)限控制實例

    struts2如何使用攔截器進(jìn)行用戶權(quán)限控制實例

    本篇文章主要介紹了struts2如何使用攔截器進(jìn)行用戶權(quán)限控制實例,非常具有實用價值,需要的朋友可以參考下
    2017-05-05
  • Mybatis一對多查詢列表屬性處理示例詳解

    Mybatis一對多查詢列表屬性處理示例詳解

    使用MyBatis進(jìn)行多表聯(lián)查的關(guān)鍵是構(gòu)建數(shù)據(jù)庫中表的字段和java中對象的屬性的映射關(guān)系,下面這篇文章主要給大家介紹了關(guān)于Mybatis一對多查詢列表屬性處理的相關(guān)資料,需要的朋友可以參考下
    2023-05-05
  • Android?Studio?中Gradle配置sonarqube插件(推薦)

    Android?Studio?中Gradle配置sonarqube插件(推薦)

    Sonarqube作為一個很實用的靜態(tài)代碼分析工具,在很多項目中都使用,本文重點給大家介紹Android?Studio?中Gradle配置sonarqube插件的相關(guān)知識,感興趣的朋友跟隨小編一起看看吧
    2022-03-03
  • 淺談Java線程池是如何運行的

    淺談Java線程池是如何運行的

    這篇文章主要介紹了淺談Java線程池是如何運行的,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • SpringBoot內(nèi)存數(shù)據(jù)導(dǎo)出成Excel的實現(xiàn)方法

    SpringBoot內(nèi)存數(shù)據(jù)導(dǎo)出成Excel的實現(xiàn)方法

    這篇文章主要給大家介紹了關(guān)于SpringBoot內(nèi)存數(shù)據(jù)導(dǎo)出成Excel的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • Java實現(xiàn)解析JSON大文件JsonReader工具詳解

    Java實現(xiàn)解析JSON大文件JsonReader工具詳解

    這篇文章主要介紹了Java實現(xiàn)解析JSON大文件的工具JsonReader使用方法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2023-01-01
  • java實現(xiàn)CSV 字段分割

    java實現(xiàn)CSV 字段分割

    這篇文章主要介紹了java實現(xiàn)CSV 字段分割的相關(guān)資料,需要的朋友可以參考下
    2015-07-07
  • 探索Java中的IP屬地獲取技術(shù)

    探索Java中的IP屬地獲取技術(shù)

    這篇文章主要為大家介紹了Java中的IP屬地獲取的技術(shù)探索,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10

最新評論

英吉沙县| 武宁县| 麟游县| 阳江市| 淅川县| 静安区| 通州市| 巴青县| 枣庄市| 万盛区| 云南省| 沁水县| 南江县| 长春市| 分宜县| 新民市| 石狮市| 大冶市| 台江县| 巴青县| 禹城市| 青州市| 桓仁| 高唐县| 象山县| 漳浦县| 滨海县| 土默特右旗| 成武县| 南岸区| 沁水县| 阳西县| 余江县| 巫溪县| 五大连池市| 永济市| 武功县| 漠河县| 辛集市| 新田县| 株洲市|