真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

什么是JVM直接內(nèi)存

本篇內(nèi)容介紹了“什么是JVM直接內(nèi)存”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

創(chuàng)新互聯(lián)-專業(yè)網(wǎng)站定制、快速模板網(wǎng)站建設(shè)、高性價比昌邑網(wǎng)站開發(fā)、企業(yè)建站全套包干低至880元,成熟完善的模板庫,直接使用。一站式昌邑網(wǎng)站制作公司更省心,省錢,快速模板網(wǎng)站建設(shè)找我們,業(yè)務(wù)覆蓋昌邑地區(qū)。費用合理售后完善,10多年實體公司更值得信賴。

JDK7和JDK8的內(nèi)存結(jié)構(gòu)對比

什么是JVM直接內(nèi)存

從上面的圖中可以看到Java8相比Java7來講將方法區(qū)的實現(xiàn),從非堆空間(其實邏輯與堆相連,所屬于運行時數(shù)據(jù)區(qū)內(nèi)部)遷移到了本地內(nèi)存中,不會造成FullGC過多的壓力以及與老年代的耦合度過高的問題,減少FullGC的掃描范圍,從而改為手動去回收機(jī)制(也可以自動回收需要配置調(diào)整)。 之前的文章里面介紹了JVM的運行時數(shù)據(jù)區(qū)的相關(guān)介紹,一直對直接內(nèi)存的研究和學(xué)習(xí)較少,現(xiàn)在我們就開始介紹一下直接內(nèi)存的分配方式以及回收方式。

直接內(nèi)存的定義

1. 常見于NIO操作時,用于數(shù)據(jù)緩沖區(qū)(ByteBuffer.allocate),當(dāng)然也可以采用Unsafe類進(jìn)行native方法運作進(jìn)行申請直接內(nèi)存

2. 分配回收成本較高(屬于操作系統(tǒng)內(nèi)存),但讀寫性能高。(因為直接內(nèi)存不需要經(jīng)過JVM解釋器進(jìn)行地址映射轉(zhuǎn)換到系統(tǒng)真正內(nèi)存,故此讀寫速度會比堆內(nèi)存在快很多,但是申請和回收機(jī)制角度而言復(fù)雜,因為屬于直接由操作系統(tǒng)進(jìn)行管理,而非JVM直接進(jìn)行管理。

3. 不受JVM內(nèi)存回收管理(依舊存在內(nèi)存溢出的問題),此外受限制與操作系統(tǒng)物理內(nèi)存,以及我們可以手動設(shè)置它的閾值(MaxDirectMemory),默認(rèn)情況下來講直接內(nèi)存幾乎沒有限制(當(dāng)沒有超出物理內(nèi)存的控制而言)

4. jvm的內(nèi)存分配與回收是自動的,不需要手動調(diào)用任何的方法,但是直接內(nèi)存需要我們手動調(diào)用方法。

直接內(nèi)存基本使用(IO操作舉例)

  1. Java堆內(nèi)存:

什么是JVM直接內(nèi)存

  1. 使用直接內(nèi)存后,可以減少步驟:

什么是JVM直接內(nèi)存

可以看出來,直接內(nèi)存無需進(jìn)行與java堆內(nèi)存進(jìn)行映射和轉(zhuǎn)換,可以直接去操作系統(tǒng)內(nèi)存。

直接內(nèi)存導(dǎo)致的內(nèi)存溢出問題

書寫程序:每次都分配直接內(nèi)存,直到內(nèi)存溢出

public class Test1 {
    static int _100Mb=1024*1024*100;

    public static void main(String[] args) {
        List list=new ArrayList<>();
        int i=0;
        try {
           while (true){
               ByteBuffer byteBuffer=ByteBuffer.allocateDirect(_100Mb);
               list.add(byteBuffer);
               i++;
           }
        }finally {
            System.out.println(i);
        }
    }
}

測試結(jié)果:

Exception in thread "main" java.lang.OutOfMemoryError: Direct buffer memory
    at java.nio.Bits.reserveMemory(Bits.java:694)
    at java.nio.DirectByteBuffer.(DirectByteBuffer.java:123)
    at java.nio.ByteBuffer.allocateDirect(ByteBuffer.java:311)
    at pers.zhb.test.Test1.main(Test1.java:15)

直接內(nèi)存的分配與回收(底層通過Unsafe對象管理)

直接內(nèi)存的分配與回收

運行程序前:

什么是JVM直接內(nèi)存

直接內(nèi)存的分配與釋放程序:

public class Test1 {
    static int _1Gb=1024*1024*1024;
    public static void main(String[] args) throws IOException {
        ByteBuffer byteBuffer=ByteBuffer.allocateDirect(_1Gb);
        System.out.println("分配完畢");
        System.in.read();
        System.out.println("開始釋放");
        byteBuffer=null;
        System.gc();
    }
}

分配直接內(nèi)存后: 什么是JVM直接內(nèi)存

可以看出來相關(guān)的多出一個java的進(jìn)程,并且內(nèi)存占用1037M,所以也證實了我們的猜測和預(yù)想。

在IDEA的控制臺點擊回車對內(nèi)存進(jìn)行釋放:

什么是JVM直接內(nèi)存

可以看到恢復(fù)到了原始的狀態(tài)。

控制臺打印出分配與回收的提示:

分配完畢
開始釋放
Process finished with exit code 0

其中System.gc() ,強(qiáng)制執(zhí)行FullGC,回收掉byteBuffer對象

至此,我們的推測全部驗證通過,直接內(nèi)存會采用另外一個進(jìn)程去存儲相關(guān)的系統(tǒng)內(nèi)存區(qū)域,并且不屬于jvm內(nèi)存之內(nèi)的管理。

Unsafe實現(xiàn)對直接內(nèi)存的分配與回收:
public class Test1 {
    static int _1Gb=1024*1024*1024;
    public static void main(String[] args) throws IOException {
        Unsafe unsafe=getUnsafe();
        //分配內(nèi)存
        long base=unsafe.allocateMemory(_1Gb);
        unsafe.setMemory(base,_1Gb,(byte)0);
        System.in.read();
        //釋放內(nèi)存
        unsafe.freeMemory(base);
        System.in.read();
    }
	
    public static Unsafe getUnsafe(){
        Field field= null;
        try {
            field = Unsafe.class.getDeclaredField("theUnsafe");
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        field.setAccessible(true);
        Unsafe unsafe= null;
        try {
            unsafe = (Unsafe)field.get(null);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return unsafe;
    }
}

jvm的內(nèi)存分配與回收是自動的,不需要手動調(diào)用任何的方法,但是直接內(nèi)存需要我們手動調(diào)用方法。

ByteBuffer源碼

ByteBuffer (屬于工具方法、工廠方法)

ByteBuffer byteBuffer= ByteBuffer.allocateDirect(_1Gb);

allocateDirect(分配內(nèi)存方法)

public static ByteBuffer allocateDirect(int capacity) {
    return new DirectByteBuffer(capacity);
}

DirectByteBuffer(直接內(nèi)存的對象)

DirectByteBuffer(int cap) {
        super(-1, 0, cap, cap);
        boolean pa = VM.isDirectMemoryPageAligned();
        int ps = Bits.pageSize();
        long size = Math.max(1L, (long)cap + (pa ? ps : 0));
        Bits.reserveMemory(size, cap);

        long base = 0;
        try {
            base = unsafe.allocateMemory(size);
        } catch (OutOfMemoryError x) {
            Bits.unreserveMemory(size, cap);
            throw x;
        }
        unsafe.setMemory(base, size, (byte) 0);
        if (pa && (base % ps != 0)) {
            // Round up to page boundary
            address = base + ps - (base & (ps - 1));
        } else {
            address = base;
        }
        cleaner = Cleaner.create(this, new Deallocator(base, size, cap));
        att = null;
 }

底層用到的依舊是unsafe對象

優(yōu)缺點

優(yōu)點

  • 減少了垃圾回收

堆外內(nèi)存是直接受操作系統(tǒng)管理(不是JVM)。這樣做能保持一個較小的堆內(nèi)內(nèi)存,以減少垃圾收集對應(yīng)用的影響。

  • 提升IO速度

堆內(nèi)內(nèi)存由JVM管理,屬于“用戶態(tài)”;而堆外內(nèi)存由OS管理,屬于“內(nèi)核態(tài)”。如果從堆內(nèi)向磁盤寫數(shù)據(jù)時,數(shù)據(jù)會被先復(fù)制到堆外內(nèi)存,即內(nèi)核緩沖區(qū),然后再由OS寫入磁盤,使用堆外內(nèi)存避免了這個操作。

缺點

  • 沒有JVM協(xié)助管理內(nèi)存,需要我們自己手動來管理堆外內(nèi)存,防止內(nèi)存溢出同時也為了避免一直有FULL GC,最終導(dǎo)致物理內(nèi)存被耗完。

我們會指定直接內(nèi)存的最大值,通過-XX:MaxDirectMemorySize來指定,當(dāng)達(dá)到閾值的時候,調(diào)用system.gc來進(jìn)行一次full gc,把那些沒有被使用的直接內(nèi)存回收掉。

  • 此外,分配直接內(nèi)存和回收內(nèi)存的性能和速度也比較復(fù)雜,所以成本也會很高,特別是回收需要FullGC、分配內(nèi)存的時候,需要切換一次用戶態(tài)到系統(tǒng)態(tài)的操作,分配直接內(nèi)存,從而用用戶態(tài)的句柄來引用系統(tǒng)態(tài)的內(nèi)存空間。

“什么是JVM直接內(nèi)存”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!


文章題目:什么是JVM直接內(nèi)存
本文鏈接:http://weahome.cn/article/jshoes.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部