电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

您的位置:首頁技術文章
文章詳情頁

Java基礎之Unsafe內存操作不安全類詳解

瀏覽:121日期:2022-08-11 09:52:21
簡介

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

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

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

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

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;

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

Unsafe 靜態加載

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 構造函數

private Unsafe() {}

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

Unsafe 實例化方法

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

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

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

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

2、通過 Java 反射機制,暴力獲取。

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

Unsafe 內存管理

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

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

Unsafe 獲取偏移量

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

Unsafe 檢查類初始化

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

Unsafe 從指定位置讀取

// 從指定內存地址處開始讀取一個bytepublic native byte getByte(long var1);// 從指定內存地址處開始讀取一個short public native short getShort(long var1);// 從指定內存地址處開始讀取一個char public native char getChar(long var1);// 從指定內存地址處開始讀取一個int public native int getInt(long var1);// 從指定內存地址處開始讀取一個long public native long getLong(long var1);// 從指定內存地址處開始讀取一個float public native float getFloat(long var1);// 從指定內存地址處開始讀取一個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);

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

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

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

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

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

Unsafe 線程的掛起和恢復

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

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

public native void unpark(Object var1);

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

Unsafe 內存屏障

public native void loadFence();

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

public native void storeFence();

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

public native void fullFence();

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

Unsafe 其他

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

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

public native void throwException(Throwable ee);

繞過檢測機制直接拋出異常。

到此這篇關于Java基礎之Unsafe內存操作不安全類詳解的文章就介紹到這了,更多相關Unsafe內存操作不安全類內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: Java
相關文章:
主站蜘蛛池模板: 臭氧实验装置_实验室臭氧发生器-北京同林臭氧装置网 | 软文发布平台 - 云软媒网络软文直编发布营销推广平台 | 刺绳_刀片刺网_刺丝滚笼_不锈钢刺绳生产厂家_安平县浩荣金属丝网制品有限公司-安平县浩荣金属丝网制品有限公司 | 安驭邦官网-双向万能直角铣头,加工中心侧铣头,角度头[厂家直销] 闸阀_截止阀_止回阀「生产厂家」-上海卡比阀门有限公司 | 大米加工设备|大米加工机械|碾米成套设备|大米加工成套设备-河南成立粮油机械有限公司 | 螺杆泵_中成泵业| 光照全温振荡器(智能型)-恒隆仪器| 冷水机-工业冷水机-冷水机组-欧科隆品牌保障 | 拖鞋定制厂家-品牌拖鞋代加工厂-振扬实业中国高端拖鞋大型制造商 | 阿米巴企业经营-阿米巴咨询管理-阿米巴企业培训-广东键锋企业管理咨询有限公司 | 报警器_家用防盗报警器_烟雾报警器_燃气报警器_防盗报警系统厂家-深圳市刻锐智能科技有限公司 | 复合肥,化肥厂,复合肥批发,化肥代理,复合肥品牌-红四方 | YJLV22铝芯铠装电缆-MYPTJ矿用高压橡套电缆-天津市电缆总厂 | 体检车_移动CT车_CT检查车_CT车_深圳市艾克瑞电气有限公司移动CT体检车厂家-深圳市艾克瑞电气有限公司 | 电动打包机_气动打包机_钢带捆扎机_废纸打包机_手动捆扎机 | 附着力促进剂-尼龙处理剂-PP处理剂-金属附着力处理剂-东莞市炅盛塑胶科技有限公司 | 广州二手电缆线回收,旧电缆回收,广州铜线回收-广东益福电缆线回收公司 | 杭州门窗厂家_阳光房_包阳台安装电话-杭州窗猫铝合金门窗 | YJLV22铝芯铠装电缆-MYPTJ矿用高压橡套电缆-天津市电缆总厂 | 探伤仪,漆膜厚度测试仪,轮胎花纹深度尺厂家-淄博创宇电子 | 船老大板材_浙江船老大全屋定制_船老大官网 | 广州办公室设计,办公室装修,写字楼设计,办公室装修公司_德科 | 上海办公室装修公司_办公室设计_直营办公装修-羚志悦装 | 工业rfid读写器_RFID工业读写器_工业rfid设备厂商-ANDEAWELL | 温州中研白癜风专科_温州治疗白癜风_温州治疗白癜风医院哪家好_温州哪里治疗白癜风 | 耐磨陶瓷,耐磨陶瓷管道_厂家-淄博拓创陶瓷科技 | 欧盟ce检测认证_reach检测报告_第三方检测中心-深圳市威腾检验技术有限公司 | 仿真茅草_人造茅草瓦价格_仿真茅草厂家_仿真茅草供应-深圳市科佰工贸有限公司 | QQ房产导航-免费收录优秀房地产网站_房地产信息网 | 上海乾拓贸易有限公司-日本SMC电磁阀_德国FESTO电磁阀_德国FESTO气缸 | WF2户外三防照明配电箱-BXD8050防爆防腐配电箱-浙江沃川防爆电气有限公司 | 防火阀、排烟防火阀、电动防火阀产品生产销售商-德州凯亿空调设备有限公司 | 污水处理设备维修_污水处理工程改造_机械格栅_过滤设备_气浮设备_刮吸泥机_污泥浓缩罐_污水处理设备_污水处理工程-北京龙泉新禹科技有限公司 | 深圳标识制作公司-标识标牌厂家-深圳广告标识制作-玟璟广告-深圳市玟璟广告有限公司 | 开平机_纵剪机厂家_开平机生产厂家|诚信互赢-泰安瑞烨精工机械制造有限公司 | 沙盘模型公司_沙盘模型制作公司_建筑模型公司_工业机械模型制作厂家 | 专业深孔加工_东莞深孔钻加工_东莞深孔钻_东莞深孔加工_模具深孔钻加工厂-东莞市超耀实业有限公司 | Pos机办理_个人商户免费POS机申请-拉卡拉办理网 | 高低温万能试验机_拉力试验机_拉伸试验机-馥勒仪器科技(上海)有限公司 | 校服厂家,英伦校服定做工厂,园服生产定制厂商-东莞市艾咪天使校服 | 房车价格_依维柯/大通/东风御风/福特全顺/江铃图片_云梯搬家车厂家-程力专用汽车股份有限公司 |