成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Java Nio FileChannel堆內堆外數據讀寫全流程分析及使用

開發 前端
CPU將page cache數據拷貝到DirectByteBuffer,因為page cache屬于內核空間,JVM進程無法直接尋址。這里是發生第二次數據拷貝。

背景

java nio中文件讀寫不管是普通文件讀寫,還是基于mmap實現零拷貝,都離不開FileChannel這個類。

隨便打開RocketMQ 源碼搜索FileChannel。

就可以看到使用頻率。

圖片圖片

kafka也是。

圖片圖片

所以在java中文件讀寫FileChannel尤為重用。

java文件讀寫全流程

圖片圖片

這里說的僅僅是FileChannel基于堆內存(HeapByteBuffer)的文件讀寫。

如果是mmap或者堆外內存,可能有些步驟會省略,相當于有一些優化。

  1. FileChannel調用read,將HeapByteBuffer拷貝到DirectByteBuffer。
  2. JVM在native層使用read系統調用進行文件讀取, 這里需要進行上下文切換,從用戶態進入內核態。
  3. JVM 進程進入虛擬文件系統層,查看文件數據再page cache是否緩存,如果有則直接從page cache讀取并返回到DirectByteBuffer。
  4. 如果請求文件數據不在page caceh,則進入文件系統。通過塊驅動設備進行真正的IO,并進行文件預讀,比如讀取的文件可能只有1-10,但是會將1-20都讀取。
  5. 磁盤控制器DMA將磁盤中的數據拷貝到page cache中。這里發生了一次數據拷貝(非CPU拷貝)。
  6. CPU將page cache數據拷貝到DirectByteBuffer,因為page cache屬于內核空間,JVM進程無法直接尋址。這里是發生第二次數據拷貝。
  7. JVM進程從內核態切換回用戶態,這里如果使用的是堆內存(HeapByteBuffer),實際還需要將堆外內存DirectByteBuffer拷貝到堆內存(HeapByteBuffer)。

FileChannel讀寫文件(非MMAP)

public static void main(String[] args) {
        String filename = "小奏技術.txt";
        String content = "Hello, 小奏技術.";
        // 寫入文件
        writeFile(filename, content);
        // 讀取文件
        System.out.println("Reading from file:");
        readFile(filename);
    }

    public static void writeFile(String filename, String content) {
        // 創建文件對象
        File file = new File(filename);
        // 確保文件存在
        if (!file.exists()) {
            try {
                boolean created = file.createNewFile();
                if (!created) {
                    System.err.println("Unable to create file: " + filename);
                    return;
                }
            } catch (Exception e) {
                System.err.println("An error occurred while creating the file: " + e.getMessage());
                return;
            }
        }
        // 使用FileChannel寫入文件
        try (RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
             FileChannel fileChannel = randomAccessFile.getChannel()) {

            ByteBuffer buffer = ByteBuffer.allocate(content.getBytes().length);
            buffer.put(content.getBytes());
            buffer.flip(); // 切換到讀模式
            while (buffer.hasRemaining()) {
                fileChannel.write(buffer);
            }
        } catch (Exception e) {
            System.err.println("An error occurred while writing to the file: " + e.getMessage());
        }
    }

    public static void readFile(String filename) {
        // 使用FileChannel讀取文件
        try (RandomAccessFile randomAccessFile = new RandomAccessFile(filename, "r");
             FileChannel fileChannel = randomAccessFile.getChannel()) {

            ByteBuffer buffer = ByteBuffer.allocate((int) fileChannel.size());

            while (fileChannel.read(buffer) > 0) {
                // Do nothing, just read
            }

            // 切換到讀模式
            buffer.flip(); 

           /* while (buffer.hasRemaining()) {

                System.out.print((char) buffer.get());
            }*/
            Charset charset = StandardCharsets.UTF_8; 
            String fileContent = charset.decode(buffer).toString();
            System.out.print(fileContent);

        } catch (Exception e) {
            System.err.println("An error occurred while reading the file: " + e.getMessage());
        }
    }

這里需要注意的一個細節 我們分配的內存的方式是:

ByteBuffer.allocate()

這里我們可以進入看看源碼:

圖片圖片

實際構造的是HeapByteBuffer,也就是JVM的堆內存。

如果我們使用:

ByteBuffer.allocateDirect()

圖片圖片

則構造的是堆外內存DirectByteBuffer。

HeapByteBuffer和DirectByteBuffer文件讀寫區別

我們看看FileChannel read方法:

圖片圖片

發現IO相關的處理被封裝在IOUtil,我們繼續看看IOUtil的write方法:

圖片圖片

可以看到如果是DirectBuffer則可以直接寫。如果是HeapByteBuffer則需要轉換為DirectByteBuffer。

圖片圖片

為什么要在DirectByteBuffer做一層轉換

主要是HeapByteBuffer受JVM管理,也就是會受到GC影響。如果在進行native調用的時候發生了GC,會導致HeapByteBuffer的內容出現錯誤。具體詳細的說明可以看看這篇MappedByteBuffer VS FileChannel:從內核層面對比兩者的性能差異。講解的非常清晰。

參考

  • MappedByteBuffer VS FileChannel:從內核層面對比兩者的性能差異 
責任編輯:武曉燕 來源: 小奏技術
相關推薦

2022-02-14 15:07:48

進程FileChanne線程

2017-01-11 14:02:32

JVM源碼內存

2020-03-06 16:08:46

堆結構堆排序應用

2021-10-08 11:45:33

內存HeapByteBuf堆內

2018-04-17 14:41:41

Java堆內存溢出

2022-06-15 16:04:13

Java編程語言

2021-02-26 20:55:56

JavaNIO隨機

2024-11-15 09:14:23

JDK4NIO函數

2022-07-03 20:31:59

JVMJava虛擬機

2015-08-06 14:54:50

JavaScript分析工具OneHeap

2022-12-26 14:41:38

Linux內存

2022-04-15 07:51:12

off-heap堆外內存JVM

2022-04-29 08:05:06

內存堆外GC

2022-09-21 08:39:52

堆外內存泄露內存分布

2012-03-31 10:49:18

ibmdw

2019-02-26 14:33:22

JVM內存虛擬機

2018-06-15 08:43:33

Java堆外內存

2020-07-13 09:16:04

Java集合

2009-06-08 22:01:03

Java堆Java棧區別

2012-04-11 15:41:48

JavaNIO
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久婷婷国产麻豆91 | 色久在线 | 久久综合九九 | 先锋av资源在线 | 久久久久久久久毛片 | 成人小视频在线观看 | 亚洲精品国产a久久久久久 中文字幕一区二区三区四区五区 | 久久精品亚洲 | 美国一级片在线观看 | 欧美久久精品一级c片 | av网站观看 | 中文字幕视频网 | 亚洲三级在线观看 | 亚洲国产午夜 | 亚洲一页| 国产午夜精品视频 | av在线免费观看网址 | 国产高清久久 | 在线免费观看色 | 日本在线你懂的 | 亚洲+变态+欧美+另类+精品 | 中文字幕乱码亚洲精品一区 | 亚洲午夜网 | 人人做人人澡人人爽欧美 | 激情的网站 | 中文字幕av高清 | 久久久亚洲综合 | 欧美一区二区三区国产精品 | 久久久久久成人 | 久久精品欧美一区二区三区麻豆 | 国产一级久久久久 | 蜜臀久久99精品久久久久野外 | 国产综合精品一区二区三区 | 激情国产在线 | 亚洲国产一区二区三区在线观看 | 久久久高清 | 精品国产成人 | 亚洲国产成人av好男人在线观看 | 国产9 9在线 | 中文 | 国产原创在线观看 | 视频在线日韩 |