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

sun?unsafe類功能及使用注意事項(xiàng)詳解

 更新時(shí)間:2022年01月26日 15:09:07   作者:空無(wú)  
這篇文章主要為大家介紹了unsafe類的功能及在使用中需要注意的事項(xiàng)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步

Unsafe簡(jiǎn)介

Unsafe是位于sun.misc包下的一個(gè)類,主要提供一些用于執(zhí)行低級(jí)別、不安全操作的方法,如直接訪問(wèn)系統(tǒng)內(nèi)存資源、自主管理內(nèi)存資源等,這些方法在提升Java運(yùn)行效率、增強(qiáng)Java語(yǔ)言底層資源操作能力方面起到了很大的作用。

但由于Unsafe類使Java語(yǔ)言擁有了類似C語(yǔ)言指針一樣操作內(nèi)存空間的能力,這無(wú)疑也增加了程序發(fā)生相關(guān)指針問(wèn)題的風(fēng)險(xiǎn)。

在程序中過(guò)度、不正確使用Unsafe類會(huì)使得程序出錯(cuò)的概率變大,使得Java這種安全的語(yǔ)言變得不再“安全”,因此對(duì)Unsafe的使用一定要慎重。

獲取Unsafe實(shí)例

private static sun.misc.Unsafe getUnsafe() {
        try {
            return AccessController.doPrivileged(new PrivilegedExceptionAction<Unsafe>() {
                @Override
                public sun.misc.Unsafe run() throws Exception {
                    Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
                    for (Field f : k.getDeclaredFields()) {
                        f.setAccessible(true);
                        Object x = f.get(null);
                        if (k.isInstance(x)) {
                            return k.cast(x);
                        }
                    }
                    // The sun.misc.Unsafe field does not exist.
                    throw new Error("unsafe is null");
                }
            });
        } catch (Throwable e) {
            throw new Error("get unsafe failed", e);
        }
    }

Unsafe功能列表

  • allocateMemory/freeMemory,分配、釋放堆外內(nèi)存DirectMemory(和c/cpp中的malloc一樣)
  • CAS操作
  • copyMemory
  • defineClass(without security checks)
  • get/put address 使用堆外內(nèi)存地址進(jìn)行數(shù)據(jù)的讀寫操作
  • get/put volatile 使用堆外內(nèi)存地址進(jìn)行數(shù)據(jù)的讀寫操作 - volatile版本
  • loadFence/storeFence/fullFence 禁止指令重排序
  • park/unpark 阻塞/解除阻塞線程

Unsafe的數(shù)組操作

unsafe中,有兩個(gè)關(guān)于數(shù)組的方法:

public native int arrayBaseOffset(Class<?> arrayClass);
public native int arrayIndexScale(Class<?> arrayClass);

base offset含義

首先,在Java中,數(shù)組也是對(duì)象

In the Java programming language, arrays are objects (§4.3.1), are dynamically created, and may be assigned to variables of type Object (§4.3.2). All methods of class Object may be invoked on an array.
https://docs.oracle.com/javase/specs/jls/se7/html/jls-10.html

那么既然是對(duì)象,就會(huì)有object header,占用一部分空間,那么理解數(shù)組的base offset也就不難了

比如下面的一段JOL輸出,實(shí)際上對(duì)象的屬性數(shù)據(jù)是從OFFSET 16的位置開始的,0-12的空間被header所占用

HotSpot 64-bit VM, COOPS, 8-byte alignment
lambda.Book object internals:

 OFFSET  SIZE           TYPE DESCRIPTION                               VALUE
      0    12                (object header)                           N/A
     12     4            int Book.sales                                N/A
     16     4         String Book.title                                N/A
     20     4      LocalDate Book.publishTime                          N/A
     24     4         String Book.author                               N/A
     28     4   List<String> Book.tags                                 N/A
Instance size: 32 bytes
Space losses: 0 bytes internal + 0 bytes external = 0 bytes total

那么如果要訪問(wèn)對(duì)象的屬性數(shù)據(jù),需要基于基地址(base address)進(jìn)行偏移,基地址+基礎(chǔ)偏移(base offset)+屬性偏移(field offset)才是數(shù)據(jù)的內(nèi)存地址(邏輯),那么title屬性的內(nèi)存地址實(shí)際上就是:

book(instance).title field address = book object base address + base offset + title field offset

數(shù)組在Java里可以視為一種特殊的對(duì)象,無(wú)論什么類型的數(shù)組,他們?cè)趦?nèi)存中都會(huì)有一分基礎(chǔ)偏移的空間,和object header類似

經(jīng)過(guò)測(cè)試,64位的JVM數(shù)組類型的基礎(chǔ)偏移都是16(測(cè)試結(jié)果在不同JVM下可能會(huì)有所區(qū)別)
原始類型的基礎(chǔ)偏移都是12(測(cè)試結(jié)果在不同JVM下可能會(huì)有所區(qū)別)
可以使用JOL工具查看原始類型包裝類的offset,比如int就看Integer的,雖然jdk沒(méi)有提供函數(shù),但是通過(guò)JOL也是可以獲取的,jvm類型和對(duì)其方式匹配即可

index scale含義

就是指數(shù)組中每個(gè)元素所占用的空間大小,比如int[] scale就是4,long[] scale就是8,object[] scale就是4(指針大?。?/p>

有了這個(gè)offset,就可以對(duì)數(shù)組進(jìn)行copyMemory操作了

public native void copyMemory(Object srcBase, long srcOffset,
                                  Object destBase, long destOffset,
                                  long bytes);

array copy to direct memory

在使用copyMemory操作時(shí),需要傳入對(duì)象及對(duì)象的base offset,對(duì)于數(shù)組來(lái)說(shuō),offset就是上面介紹的offset,比如現(xiàn)在將一個(gè)數(shù)組中的數(shù)據(jù)拷貝至DirectBuffer

byte[] byte = new byte[4096];
unsafe.copyMemory(byte,ARRAY_BYTE_BASE_OFFSET,null,directAddr,4096);

之所以使用unsafe而不是ByteBuffer的方法來(lái)操作DirectBuffer,是因?yàn)锽yteBuffer不夠靈活。

比如我想把一個(gè)byte[]拷貝至DirectBuffer的某個(gè)位置中,就沒(méi)有相應(yīng)的方法;只能先設(shè)置position,然后再put(byte[], int, int),非常麻煩,而且并發(fā)訪問(wèn)時(shí)position(long)和put也是個(gè)非原子性操作

但是用unsafe來(lái)操作的話就很輕松了,直接copyMemory,直接指定address + offset就行

unsafe.copyMemory(byte,ARRAY_BYTE_BASE_OFFSET,null,directAddr,4096);

copyMemory(Object srcBase, long srcOffset, Object destBase, long destOffset, long bytes)

  • srcBase 原數(shù)據(jù)對(duì)象,可以是對(duì)象、數(shù)組(對(duì)象),也可以是Null(為Null時(shí)必須指定offset,offset就是address)
  • srcOffset 原數(shù)據(jù)對(duì)象的base offset,如果srcBase為空則此項(xiàng)為address
  • destBase 目標(biāo)數(shù)據(jù)對(duì)象,規(guī)則同src
  • destOffset 目標(biāo)數(shù)據(jù)對(duì)象的base offset,規(guī)則同src
  • bytes 要拷貝的數(shù)據(jù)大小(字節(jié)單位)

通過(guò)copyMemory方法,可以做各種拷貝操作:

對(duì)象(一般是數(shù)組)拷貝到指定堆外內(nèi)存地址

long l = unsafe.allocateMemory(1);
data2[0] = 5;
//目標(biāo)是memory address,destBase為null,destOffset為address
unsafe.copyMemory(data2,16,null,l,1);

將對(duì)象拷貝到對(duì)象

byte[] data1 = new byte[1];
data1[0] = 9;

byte[] data2 = new byte[1];
unsafe.copyMemory(data1,16,data2,16,1);

將堆外內(nèi)存地址的數(shù)據(jù)拷貝到堆內(nèi)(一般是數(shù)組)

byte[] data2 = new byte[1];

long l = unsafe.allocateMemory(1);
unsafe.putByte(l, (byte) 2);
//源數(shù)據(jù)是memory address,srcBase為null,srcOffset為address
unsafe.copyMemory(null,l,data2,16,1);

堆外內(nèi)存地址互相拷貝

long l = unsafe.allocateMemory(1);
long l2 = unsafe.allocateMemory(1);
unsafe.putByte(l, (byte) 2);
//源數(shù)據(jù)是memory address,srcBase為null,srcOffset為address
//目標(biāo)是memory address,destBase為null,destOffset為address
unsafe.copyMemory(null,l,null,l2,1);

Benchmark

sun.misc.Unsafe#putInt(java.lang.Object, long, int) & object field manual set

禁用JIT結(jié)果:

BenchmarkModeCntScoreErrorUnits
ObjectFieldSetBenchmark.manualSetthrpt28646455.472 ops/ns
ObjectFieldSetBenchmark.unsafeSetthrpt27901066.170 ops/ns

啟用JIT結(jié)果:

BenchmarkModeCntScoreErrorUnits
ObjectFieldSetBenchmark.manualSetthrpt2477232013.545 ops/ns
ObjectFieldSetBenchmark.unsafeSetthrpt2499135982.962 ops/ns

結(jié)論,幾乎沒(méi)區(qū)別

什么時(shí)候用Unsafe

一般使用DirectBuffer時(shí),需要配合Unsafe來(lái)使用,因?yàn)镈irectBuffer的內(nèi)存是分配在JVM Heap之外的,屬于C Heap,所以需要用直接操作內(nèi)存地址(邏輯),和C里malloc之后的操作方式一樣

以上就是unsafe類功能及使用注意事項(xiàng)詳解的詳細(xì)內(nèi)容,更多關(guān)于unsafe類功能及使用的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論

稷山县| 南京市| 金秀| 崇左市| 行唐县| 肃宁县| 大安市| 准格尔旗| 福清市| 江永县| 毕节市| 宜城市| 扶风县| 寿阳县| 富平县| 永平县| 双峰县| 广汉市| 青浦区| 青海省| 罗田县| 车险| 班玛县| 十堰市| 金溪县| 绩溪县| 南投县| 玉门市| 峨眉山市| 长乐市| 筠连县| 大名县| 宜春市| 那曲县| 台州市| 深圳市| 孝义市| 乐业县| 敦化市| 荔浦县| 赤城县|