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

詳細總結Java堆棧內(nèi)存、堆外內(nèi)存、零拷貝淺析與代碼實現(xiàn)

 更新時間:2021年05月14日 08:41:23   作者:JiangNanMax  
零拷貝,這是個耳熟能詳?shù)拿~,是開發(fā)崗面試中經(jīng)常提及的問題.最近在回顧Netty的基礎原理,還是把NIO中關于堆外內(nèi)存的知識點過了一遍,這里就針對堆棧內(nèi)存 堆外內(nèi)存和零拷貝這幾個概念以及相關知識做一下記錄,需要的朋友可以參考下

一、堆棧內(nèi)存

堆棧內(nèi)存,顧名思義,指的是堆內(nèi)存以及棧內(nèi)存,其中,堆內(nèi)存是由Java GC進行管理的內(nèi)存區(qū)域,而棧內(nèi)存則是線程內(nèi)存。關于棧內(nèi)存,這里不去細說。以Hotspot為例,堆內(nèi)存的簡要結構如下圖所示:

在這里插入圖片描述

而堆棧的關系,我們可以通過一行簡單的代碼來理解:

public static void main(String[] args) {
    Object o = new Object();
}

上述代碼主要完成了兩件事,new Object( ) 在堆上開辟了一塊內(nèi)存,也就是說,new Object( )是分配在堆上的;而變量o,則是在線程main的棧上面的,它指向了new Object( ) 開辟的堆內(nèi)存地址。簡單來說,程序中創(chuàng)建的對象,都存儲在堆內(nèi)存中,棧內(nèi)存包含對它的引用。

二、堆外內(nèi)存

簡單來說,除了堆棧內(nèi)存,剩下的就都是堆外內(nèi)存了(當然,這是從Java運行時內(nèi)存的角度來看),堆外內(nèi)存直接受操作系統(tǒng)管理,而不是虛擬機。而使用堆外內(nèi)存的原因,主要有幾點:

  • 一定程度上減少了GC,堆外內(nèi)存是直接受操作系統(tǒng)管理的,而不是JVM,因此使用堆外內(nèi)存的話,就可以保持一個比較小的堆內(nèi)內(nèi)存,減少垃圾回收對程序性能的影響。這一塊,在Kafka中就應用得很好,感興趣的同學可以去了解一下;
  • 還有一個更大的優(yōu)點,就是提高IO操作的效率!這里就涉及用戶態(tài)與內(nèi)核態(tài),以及內(nèi)核緩沖區(qū)的概念,具體可以看筆者之前的一篇文章Java隨筆記 - 內(nèi)核緩沖區(qū)與進程緩沖區(qū)。其中,堆內(nèi)內(nèi)存其實就是用戶進程的進程緩沖區(qū),屬于用戶態(tài),而堆外內(nèi)存由操作系統(tǒng)管理,屬于內(nèi)核態(tài)。如果從堆內(nèi)向磁盤寫數(shù)據(jù),數(shù)據(jù)會被先復制到堆外內(nèi)存,即內(nèi)核緩沖區(qū),然后再由OS寫入磁盤,但使用堆外內(nèi)存的話則可以避免這個復制操作。

在這里插入圖片描述

三、零拷貝

總結上述內(nèi)容中對堆棧內(nèi)存與堆外內(nèi)存的說明,主要解決了兩個疑問:“零拷貝”是從哪拷貝到哪?“零拷貝”是怎么優(yōu)化掉這一拷貝操作的?

  • 用戶進程需要像磁盤寫數(shù)據(jù)時,需要將用戶緩沖區(qū)(堆內(nèi)內(nèi)存)中的內(nèi)容拷貝到內(nèi)核緩沖區(qū)(堆外內(nèi)存)中,操作系統(tǒng)再將內(nèi)核緩沖區(qū)中的內(nèi)容寫進磁盤中;
  • 通過在用戶進程中,直接申請堆外內(nèi)存,存儲其需要寫進磁盤的數(shù)據(jù),就能夠省掉上述拷貝操作。

在Java中,提供了一些使用堆外內(nèi)存以及DMA的方法,能夠在很大程度上優(yōu)化用戶進程的IO效率。這里,給出一份拷貝文件的代碼,分別使用BIO、NIO和使用堆外內(nèi)存的NIO進行文件復制,簡單對比其耗時。

這里我使用一個200MB左右的pdf文件進行拷貝操作,你可以另外指定更大的文件,文件越大對比越明顯。這里我運行出來的延時,BIO的平均耗時1500ms上下,NIO耗時120ms左右, 使用堆外內(nèi)存的NIO耗時100ms上下。

package top.jiangnanmax.nio;

import java.io.*;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;

/**
 * @author jiangnanmax
 * @email jiangnanmax@gmail.com
 * @description CopyCompare
 * @date 2021/5/7
 **/

public class CopyCompare {

    public static void main(String[] args) throws Exception {
        String inputFile = "/tmp/nio/input/HyperLedger.pdf";
        String outputFile = "/tmp/nio/output/HyperLedger.pdf";

        long start = System.currentTimeMillis();

        nioCopyByDirectMem(inputFile, outputFile);

        long end = System.currentTimeMillis();

        System.out.println("cost time: " + (end - start) + " ms");

        deleteFile(outputFile);
    }

    /**
     * 使用傳統(tǒng)IO進行文件復制
     *
     * 平均耗時 15** ms
     *
     * @param sourcePath
     * @param destPath
     */
    private static void bioCopy(String sourcePath, String destPath) throws Exception {
        File sourceFile = new File(sourcePath);
        File destFile = new File(destPath);
        if (!destFile.exists()) {
            destFile.createNewFile();
        }

        FileInputStream inputStream = new FileInputStream(sourceFile);
        FileOutputStream outputStream = new FileOutputStream(destFile);

        byte[] buffer = new byte[512];
        int lenRead;

        while ((lenRead = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, lenRead);
        }

        inputStream.close();
        outputStream.close();
    }

    /**
     * 使用NIO進行文件復制,但不使用堆外內(nèi)存
     *
     * 平均耗時 1** ms, 比BIO直接快了一個數(shù)量級???
     *
     * @param sourcePath
     * @param destPath
     */
    private static void nioCopy(String sourcePath, String destPath) throws Exception {
        File sourceFile = new File(sourcePath);
        File destFile = new File(destPath);
        if (!destFile.exists()) {
            destFile.createNewFile();
        }

        FileInputStream inputStream = new FileInputStream(sourceFile);
        FileOutputStream outputStream = new FileOutputStream(destFile);

        FileChannel inputChannel = inputStream.getChannel();
        FileChannel outputChannel = outputStream.getChannel();

        // transferFrom底層調(diào)用的應該是sendfile
        // 直接在兩個文件描述符之間進行了數(shù)據(jù)傳輸
        // DMA

        outputChannel.transferFrom(inputChannel, 0, inputChannel.size());

        inputChannel.close();
        outputChannel.close();
        inputStream.close();
        outputStream.close();

    }

    /**
     * 使用NIO進行文件復制,并使用堆外內(nèi)存
     *
     * 平均耗時100ms上下,比沒使用堆外內(nèi)存的NIO快一點
     *
     * @param sourcePath
     * @param destPath
     */
    private static void nioCopyByDirectMem(String sourcePath, String destPath) throws Exception {
        File sourceFile = new File(sourcePath);
        File destFile = new File(destPath);
        if (!destFile.exists()) {
            destFile.createNewFile();
        }

        FileInputStream inputStream = new FileInputStream(sourceFile);
        FileOutputStream outputStream = new FileOutputStream(destFile);

        FileChannel inputChannel = inputStream.getChannel();
        FileChannel outputChannel = outputStream.getChannel();

        MappedByteBuffer buffer = inputChannel.map(FileChannel.MapMode.READ_ONLY, 0, inputChannel.size());

        outputChannel.write(buffer);

        inputChannel.close();
        outputChannel.close();
        inputStream.close();
        outputStream.close();

    }

    /**
     * 刪除目標文件
     *
     * @param target
     */
    private static void deleteFile(String target) {
        File file = new File(target);
        file.delete();
    }

}

到此這篇關于詳細總結Java堆棧內(nèi)存、堆外內(nèi)存、零拷貝淺析與代碼實現(xiàn)的文章就介紹到這了,更多相關Java堆棧內(nèi)存 堆外內(nèi)存 零拷貝淺析內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • java實現(xiàn)的日期時間轉換工具類完整示例

    java實現(xiàn)的日期時間轉換工具類完整示例

    這篇文章主要介紹了java實現(xiàn)的日期時間轉換工具類,結合完整實例形式分析了java針對日期時間常見的轉換、計算、格式化等相關操作與封裝技巧,需要的朋友可以參考下
    2019-10-10
  • Spring的Bean生命周期之BeanDefinition詳解

    Spring的Bean生命周期之BeanDefinition詳解

    這篇文章主要介紹了Spring的Bean生命周期之BeanDefinition詳解,在spring bean創(chuàng)建過程 依賴 BeanDefinition 中的信息處理bean的生產(chǎn),BeanDefinition 是 Spring Framework 中定義 Bean 的配置元信息接口,需要的朋友可以參考下
    2023-12-12
  • MyBatis-Plus 快速入門案例(小白教程)

    MyBatis-Plus 快速入門案例(小白教程)

    這篇文章主要介紹了MyBatis-Plus 快速入門案例(小白教程),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2020-08-08
  • java調(diào)用shell命令并獲取執(zhí)行結果的示例

    java調(diào)用shell命令并獲取執(zhí)行結果的示例

    今天小編就為大家分享一篇java調(diào)用shell命令并獲取執(zhí)行結果的示例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-07-07
  • Java多線程中的Exchanger應用簡析

    Java多線程中的Exchanger應用簡析

    這篇文章主要介紹了Java多線程中的Exchanger應用簡析,Exchanger提供了一個同步點exchange方法,兩個線程調(diào)用exchange方法時,無論調(diào)用時間先后,兩個線程會互相等到線程到達exchange方法調(diào)用點,此時兩個線程可以交換數(shù)據(jù),將本線程產(chǎn)出數(shù)據(jù)傳遞給對方,需要的朋友可以參考下
    2023-12-12
  • 基于spring?@Cacheable?注解的spel表達式解析執(zhí)行邏輯

    基于spring?@Cacheable?注解的spel表達式解析執(zhí)行邏輯

    這篇文章主要介紹了spring?@Cacheable?注解的spel表達式解析執(zhí)行邏輯,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • 詳解Mybatis的分頁插件

    詳解Mybatis的分頁插件

    這篇文章主要介紹了詳解Mybatis的分頁插件,在 Mybatis中,如何對數(shù)據(jù)進行分頁是一個非常常見的問題,現(xiàn)在,我們可以通過使用 Mybatis 的分頁插件來實現(xiàn)對數(shù)據(jù)的分頁,需要的朋友可以參考下
    2023-05-05
  • java如何調(diào)用kettle設置變量和參數(shù)

    java如何調(diào)用kettle設置變量和參數(shù)

    文章簡要介紹了如何在Java中調(diào)用Kettle,并重點討論了變量和參數(shù)的區(qū)別,以及在Java代碼中如何正確設置和使用這些變量,避免覆蓋Kettle中已設置的變量,作者分享了個人經(jīng)驗,并鼓勵大家參考和使用腳本之家
    2025-01-01
  • java使用wait和notify實現(xiàn)線程通信

    java使用wait和notify實現(xiàn)線程通信

    這篇文章主要為大家詳細介紹了java如何使用wait和notify實現(xiàn)線程之間通信,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2023-10-10
  • SpringBoot整合Kafka工具類的詳細代碼

    SpringBoot整合Kafka工具類的詳細代碼

    Kafka是一種高吞吐量的分布式發(fā)布訂閱消息系統(tǒng),它可以處理消費者在網(wǎng)站中的所有動作流數(shù)據(jù),這篇文章主要介紹了SpringBoot整合Kafka工具類的代碼詳解,需要的朋友可以參考下
    2022-09-09

最新評論

无棣县| 岑巩县| 和硕县| 文化| 中西区| 天镇县| 辉县市| 泸溪县| 高青县| 盱眙县| 西城区| 金寨县| 绥中县| 伊宁县| 吉林省| 霞浦县| 温泉县| 阿图什市| 竹山县| 江陵县| 双牌县| 伊川县| 得荣县| 慈利县| 泾源县| 永登县| 阿鲁科尔沁旗| 新田县| 舞钢市| 高雄市| 怀仁县| 庆元县| 西丰县| 关岭| 潢川县| 河源市| 霍山县| 澄江县| 康平县| 平舆县| 宣汉县|