欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

一、堆棧內(nèi)存

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

在這里插入圖片描述

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

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

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

二、堆外內(nèi)存

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

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

在這里插入圖片描述

三、零拷貝

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

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

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

這里我使用一個(gè)200MB左右的pdf文件進(jìn)行拷貝操作,你可以另外指定更大的文件,文件越大對比越明顯。這里我運(yùn)行出來的延時(shí),BIO的平均耗時(shí)1500ms上下,NIO耗時(shí)120ms左右, 使用堆外內(nèi)存的NIO耗時(shí)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進(jìn)行文件復(fù)制
     *
     * 平均耗時(shí) 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進(jìn)行文件復(fù)制,但不使用堆外內(nèi)存
     *
     * 平均耗時(shí) 1** ms, 比BIO直接快了一個(gè)數(shù)量級(jí)???
     *
     * @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)用的應(yīng)該是sendfile
        // 直接在兩個(gè)文件描述符之間進(jìn)行了數(shù)據(jù)傳輸
        // DMA

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

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

    }

    /**
     * 使用NIO進(jìn)行文件復(fù)制,并使用堆外內(nèi)存
     *
     * 平均耗時(shí)100ms上下,比沒使用堆外內(nèi)存的NIO快一點(diǎn)
     *
     * @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();

    }

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

}

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

相關(guān)文章

  • Spring Boot中整合PageHelper實(shí)現(xiàn)分頁功能詳細(xì)步驟

    Spring Boot中整合PageHelper實(shí)現(xiàn)分頁功能詳細(xì)步驟

    在Spring Boot項(xiàng)目中整合PageHelper并實(shí)現(xiàn)分頁查詢功能的全部步驟,通過以上配置和代碼,我們可以輕松地實(shí)現(xiàn)數(shù)據(jù)庫分頁查詢,提高了開發(fā)效率并改善了用戶體驗(yàn),感興趣的朋友跟隨小編一起看看吧
    2024-05-05
  • 使用Java實(shí)現(xiàn)三種等級(jí)的掃雷游戲(完整版)

    使用Java實(shí)現(xiàn)三種等級(jí)的掃雷游戲(完整版)

    掃雷是一款大眾類的益智小游戲,根據(jù)點(diǎn)擊格子出現(xiàn)的數(shù)字找出所有非雷格子,同時(shí)避免踩雷,踩到一個(gè)雷即全盤皆輸,下面這篇文章主要給大家介紹了關(guān)于使用Java實(shí)現(xiàn)三種等級(jí)的掃雷游戲的相關(guān)資料,需要的朋友可以參考下
    2023-01-01
  • Java通過FTP服務(wù)器上傳下載文件的方法

    Java通過FTP服務(wù)器上傳下載文件的方法

    本文介紹了如何使用Apache Jakarta Commons Net(commons-net-3.3.jar)基于FileZilla Server服務(wù)器實(shí)現(xiàn)FTP服務(wù)器上文件的上傳/下載/刪除等操作,需要的朋友可以參考下
    2015-07-07
  • Eclipse安裝配置方法圖文教程

    Eclipse安裝配置方法圖文教程

    這篇文章主要為大家詳細(xì)介紹了Eclipse安裝配置方法圖文教程,感興趣的小伙伴們可以參考一下
    2016-06-06
  • Java中IO流的BufferedOutputStream和FileOutputStream對比

    Java中IO流的BufferedOutputStream和FileOutputStream對比

    這篇文章主要介紹了Java中IO流的BufferedOutputStream和FileOutputStream對比,不帶緩沖的操作,每讀一個(gè)字節(jié)就要寫入一個(gè)字節(jié),由于涉及磁盤的IO操作相比內(nèi)存的操作要慢很多,所以在讀寫的字節(jié)比較少的情況下,效率比較低,需要的朋友可以參考下
    2023-07-07
  • 解析Spring Boot內(nèi)嵌tomcat關(guān)于getServletContext().getRealPath獲取得到臨時(shí)路徑的問題

    解析Spring Boot內(nèi)嵌tomcat關(guān)于getServletContext().getRealPath獲取得到臨時(shí)

    大家都很糾結(jié)這個(gè)問題在使用getServletContext().getRealPath()得到的是臨時(shí)文件的路徑,每次重啟服務(wù),這個(gè)臨時(shí)文件的路徑還好變更,下面小編通過本文給大家分享Spring Boot內(nèi)嵌tomcat關(guān)于getServletContext().getRealPath獲取得到臨時(shí)路徑的問題,一起看看吧
    2021-05-05
  • java 中如何獲取字節(jié)碼文件的相關(guān)內(nèi)容

    java 中如何獲取字節(jié)碼文件的相關(guān)內(nèi)容

    這篇文章主要介紹了java 中如何獲取字節(jié)碼文件的相關(guān)內(nèi)容的相關(guān)資料,需要的朋友可以參考下
    2017-04-04
  • java客戶端Etcd官方倉庫jetcd中KeepAlive接口實(shí)現(xiàn)

    java客戶端Etcd官方倉庫jetcd中KeepAlive接口實(shí)現(xiàn)

    這篇文章主要為大家介紹了java客戶端Etcd官方倉庫jetcd中KeepAlive接口實(shí)現(xiàn),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,多多加薪
    2022-02-02
  • SpringBoot?spring.factories加載時(shí)機(jī)分析

    SpringBoot?spring.factories加載時(shí)機(jī)分析

    這篇文章主要為大家介紹了SpringBoot?spring.factories加載時(shí)機(jī)分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • Java單例模式簡單示例

    Java單例模式簡單示例

    這篇文章主要介紹了Java單例模式,結(jié)合實(shí)例形式簡單分析了java單例模式的定義與使用技巧,需要的朋友可以參考下
    2017-06-06

最新評(píng)論