91欧美超碰AV自拍|国产成年人性爱视频免费看|亚洲 日韩 欧美一厂二区入|人人看人人爽人人操aV|丝袜美腿视频一区二区在线看|人人操人人爽人人爱|婷婷五月天超碰|97色色欧美亚州A√|另类A√无码精品一级av|欧美特级日韩特级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

JAVA中NIO通過MappedByteBuffer操作大文件

汽車玩家 ? 來源:IT知識(shí)課堂 ? 作者:IT知識(shí)課堂 ? 2020-05-05 23:42 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

java io操作中通常采用BufferedReader,BufferedInputStream等帶緩沖的IO類處理大文件,不過java nio中引入了一種基于MappedByteBuffer操作大文件的方式,其讀寫性能極高,本文會(huì)介紹其性能如此高的內(nèi)部實(shí)現(xiàn)原理。

內(nèi)存管理

在深入MappedByteBuffer之前,先看看計(jì)算機(jī)內(nèi)存管理的幾個(gè)術(shù)語:

MMC:CPU的內(nèi)存管理單元。

物理內(nèi)存:即內(nèi)存條的內(nèi)存空間。

虛擬內(nèi)存:計(jì)算機(jī)系統(tǒng)內(nèi)存管理的一種技術(shù)。它使得應(yīng)用程序認(rèn)為它擁有連續(xù)的可用的內(nèi)存(一個(gè)連續(xù)完整的地址空間),而實(shí)際上,它通常是被分隔成多個(gè)物理內(nèi)存碎片,還有部分暫時(shí)存儲(chǔ)在外部磁盤存儲(chǔ)器上,在需要時(shí)進(jìn)行數(shù)據(jù)交換。

頁面文件:操作系統(tǒng)反映構(gòu)建并使用虛擬內(nèi)存的硬盤空間大小而創(chuàng)建的文件,在windows下,即pagefile.sys文件,其存在意味著物理內(nèi)存被占滿后,將暫時(shí)不用的數(shù)據(jù)移動(dòng)到硬盤上。

缺頁中斷:當(dāng)程序試圖訪問已映射在虛擬地址空間中但未被加載至物理內(nèi)存的一個(gè)分頁時(shí),由MMC發(fā)出的中斷。如果操作系統(tǒng)判斷此次訪問是有效的,則嘗試將相關(guān)的頁從虛擬內(nèi)存文件中載入物理內(nèi)存。

為什么會(huì)有虛擬內(nèi)存和物理內(nèi)存的區(qū)別?
如果正在運(yùn)行的一個(gè)進(jìn)程,它所需的內(nèi)存是有可能大于內(nèi)存條容量之和的,如內(nèi)存條是256M,程序卻要?jiǎng)?chuàng)建一個(gè)2G的數(shù)據(jù)區(qū),那么所有數(shù)據(jù)不可能都加載到內(nèi)存(物理內(nèi)存),必然有數(shù)據(jù)要放到其他介質(zhì)中(比如硬盤),待進(jìn)程需要訪問那部分?jǐn)?shù)據(jù)時(shí),再調(diào)度進(jìn)入物理內(nèi)存。

什么是虛擬內(nèi)存地址和物理內(nèi)存地址?
假設(shè)你的計(jì)算機(jī)是32位,那么它的地址總線是32位的,也就是它可以尋址00xFFFFFFFF(4G)的地址空間,但如果你的計(jì)算機(jī)只有256M的物理內(nèi)存0x0x0FFFFFFF(256M),同時(shí)你的進(jìn)程產(chǎn)生了一個(gè)不在這256M地址空間中的地址,那么計(jì)算機(jī)該如何處理呢?回答這個(gè)問題前,先說明計(jì)算機(jī)的內(nèi)存分頁機(jī)制。

計(jì)算機(jī)會(huì)對(duì)虛擬內(nèi)存地址空間(32位為4G)進(jìn)行分頁產(chǎn)生頁(page),對(duì)物理內(nèi)存地址空間(假設(shè)256M)進(jìn)行分頁產(chǎn)生頁幀(page frame),頁和頁幀的大小一樣,所以虛擬內(nèi)存頁的個(gè)數(shù)勢(shì)必要大于物理內(nèi)存頁幀的個(gè)數(shù)。在計(jì)算機(jī)上有一個(gè)頁表(page table),就是映射虛擬內(nèi)存頁到物理內(nèi)存頁的,更確切的說是頁號(hào)到頁幀號(hào)的映射,而且是一對(duì)一的映射。
問題來了,虛擬內(nèi)存頁的個(gè)數(shù) > 物理內(nèi)存頁幀的個(gè)數(shù),豈不是有些虛擬內(nèi)存頁的地址永遠(yuǎn)沒有對(duì)應(yīng)的物理內(nèi)存地址空間?不是的,操作系統(tǒng)是這樣處理的。操作系統(tǒng)有個(gè)頁面失效(page fault)功能。操作系統(tǒng)找到一個(gè)最少使用的頁幀,使之失效,并把它寫入磁盤,隨后把需要訪問的頁放到頁幀中,并修改頁表中的映射,保證了所有的頁都會(huì)被調(diào)度。

現(xiàn)在來看看什么是虛擬內(nèi)存地址和物理內(nèi)存地址:

虛擬內(nèi)存地址:由頁號(hào)(與頁表中的頁號(hào)關(guān)聯(lián))和偏移量(頁的小大,即這個(gè)頁能存多少數(shù)據(jù))組成。

舉個(gè)例子,有一個(gè)虛擬地址它的頁號(hào)是4,偏移量是20,那么他的尋址過程是這樣的:首先到頁表中找到頁號(hào)4對(duì)應(yīng)的頁幀號(hào)(比如為8),如果頁不在內(nèi)存中,則用失效機(jī)制調(diào)入頁,接著把頁幀號(hào)和偏移量傳給MMC組成一個(gè)物理上真正存在的地址,最后就是訪問物理內(nèi)存的數(shù)據(jù)了。

MappedByteBuffer是什么

從繼承結(jié)構(gòu)上看,MappedByteBuffer繼承自ByteBuffer,內(nèi)部維護(hù)了一個(gè)邏輯地址address。

示例

通過MappedByteBuffer讀取文件

JAVA中NIO通過MappedByteBuffer操作大文件

map過程

FileChannel提供了map方法把文件映射到虛擬內(nèi)存,通常情況可以映射整個(gè)文件,如果文件比較大,可以進(jìn)行分段映射。

FileChannel中的幾個(gè)變量:MapMode mode:內(nèi)存映像文件訪問的方式,共三種: MapMode.READ_ONLY:只讀,試圖修改得到的緩沖區(qū)將導(dǎo)致拋出異常。 MapMode.READ_WRITE:讀/寫,對(duì)得到的緩沖區(qū)的更改最終將寫入文件;但該更改對(duì)映射到同一文件的其他程序不一定是可見的。 MapMode.PRIVATE:私用,可讀可寫,但是修改的內(nèi)容不會(huì)寫入文件,只是buffer自身的改變,這種能力稱之為”copy on write”。position:文件映射時(shí)的起始位置。allocationGranularity:Memory allocation size for mapping buffers,通過native函數(shù)initIDs初始化。

接下去通過分析源碼,了解一下map過程的內(nèi)部實(shí)現(xiàn)。

通過RandomAccessFile獲取FileChannel。

JAVA中NIO通過MappedByteBuffer操作大文件

上述實(shí)現(xiàn)可以看出,由于synchronized ,只有一個(gè)線程能夠初始化FileChannel。

通過FileChannel.map方法,把文件映射到虛擬內(nèi)存,并返回邏輯地址address,實(shí)現(xiàn)如下:

JAVA中NIO通過MappedByteBuffer操作大文件

上述代碼可以看出,最終map通過native函數(shù)map0完成文件的映射工作。
1. 如果第一次文件映射導(dǎo)致OOM,則手動(dòng)觸發(fā)垃圾回收,休眠100ms后再次嘗試映射,如果失敗,則拋出異常。
2. 通過newMappedByteBuffer方法初始化MappedByteBuffer實(shí)例,不過其最終返回的是DirectByteBuffer的實(shí)例,實(shí)現(xiàn)如下:

JAVA中NIO通過MappedByteBuffer操作大文件

由于FileChannelImpl和DirectByteBuffer不在同一個(gè)包中,所以有權(quán)限訪問問題,通過AccessController類獲取DirectByteBuffer的構(gòu)造器進(jìn)行實(shí)例化。

DirectByteBuffer是MappedByteBuffer的一個(gè)子類,其實(shí)現(xiàn)了對(duì)內(nèi)存的直接操作。

get過程

MappedByteBuffer的get方法最終通過DirectByteBuffer.get方法實(shí)現(xiàn)的。

JAVA中NIO通過MappedByteBuffer操作大文件

map0()函數(shù)返回一個(gè)地址address,這樣就無需調(diào)用read或write方法對(duì)文件進(jìn)行讀寫,通過address就能夠操作文件。底層采用unsafe.getByte方法,通過(address + 偏移量)獲取指定內(nèi)存的數(shù)據(jù)。

第一次訪問address所指向的內(nèi)存區(qū)域,導(dǎo)致缺頁中斷,中斷響應(yīng)函數(shù)會(huì)在交換區(qū)中查找相對(duì)應(yīng)的頁面,如果找不到(也就是該文件從來沒有被讀入內(nèi)存的情況),則從硬盤上將文件指定頁讀取到物理內(nèi)存中(非jvm堆內(nèi)存)。

如果在拷貝數(shù)據(jù)時(shí),發(fā)現(xiàn)物理內(nèi)存不夠用,則會(huì)通過虛擬內(nèi)存機(jī)制(swap)將暫時(shí)不用的物理頁面交換到硬盤的虛擬內(nèi)存中。

性能分析

從代碼層面上看,從硬盤上將文件讀入內(nèi)存,都要經(jīng)過文件系統(tǒng)進(jìn)行數(shù)據(jù)拷貝,并且數(shù)據(jù)拷貝操作是由文件系統(tǒng)和硬件驅(qū)動(dòng)實(shí)現(xiàn)的,理論上來說,拷貝數(shù)據(jù)的效率是一樣的。
但是通過內(nèi)存映射的方法訪問硬盤上的文件,效率要比read和write系統(tǒng)調(diào)用高,這是為什么?

read()是系統(tǒng)調(diào)用,首先將文件從硬盤拷貝到內(nèi)核空間的一個(gè)緩沖區(qū),再將這些數(shù)據(jù)拷貝到用戶空間,實(shí)際上進(jìn)行了兩次數(shù)據(jù)拷貝;

map()也是系統(tǒng)調(diào)用,但沒有進(jìn)行數(shù)據(jù)拷貝,當(dāng)缺頁中斷發(fā)生時(shí),直接將文件從硬盤拷貝到用戶空間,只進(jìn)行了一次數(shù)據(jù)拷貝。

所以,采用內(nèi)存映射的讀寫效率要比傳統(tǒng)的read/write性能高。

總結(jié)

MappedByteBuffer使用虛擬內(nèi)存,因此分配(map)的內(nèi)存大小不受JVM的-Xmx參數(shù)限制,但是也是有大小限制的。

如果當(dāng)文件超出1.5G限制時(shí),可以通過position參數(shù)重新map文件后面的內(nèi)容。

MappedByteBuffer在處理大文件時(shí)的確性能很高,但也存在一些問題,如內(nèi)存占用、文件關(guān)閉不確定,被其打開的文件只有在垃圾回收的才會(huì)被關(guān)閉,而且這個(gè)時(shí)間點(diǎn)是不確定的。
javadoc中也提到:A mapped byte buffer and the file mapping that it represents remain valid until the buffer itself is garbage-collected.*

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 內(nèi)存
    +關(guān)注

    關(guān)注

    9

    文章

    3212

    瀏覽量

    76385
  • JAVA
    +關(guān)注

    關(guān)注

    20

    文章

    3002

    瀏覽量

    116459
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    飛凌嵌入式ElfBoard-文件I/O的了解探究之Linux系統(tǒng)的文件管理機(jī)制

    的inode編號(hào)。② 通過inode編號(hào)從inode table中找到對(duì)應(yīng)的inode結(jié)構(gòu)體。 ③ 根據(jù)inode結(jié)構(gòu)體記錄的信息,確定文件數(shù)據(jù)所在的block,并讀出數(shù)據(jù)。文件打開
    發(fā)表于 11-18 08:50

    Arm Neoverse CPU上大代碼量Java應(yīng)用的性能測(cè)試

    Java 虛擬機(jī) (JVM) 內(nèi)執(zhí)行。JVM 必須先通過解釋器或即時(shí) (JIT) 編譯器將字節(jié)碼轉(zhuǎn)換為機(jī)器碼,而運(yùn)行時(shí)生成的機(jī)器碼對(duì) Java 應(yīng)用的效率和性能至關(guān)重要。
    的頭像 發(fā)表于 11-05 11:25 ?765次閱讀
    Arm Neoverse CPU上大代碼量<b class='flag-5'>Java</b>應(yīng)用的性能測(cè)試

    Air8000工業(yè)引擎WiFi AP文件管理功能操作指南

    、WiFi AP 文件管理系統(tǒng)概述 ? 本文檔介紹基于 Air8000 工業(yè)引擎實(shí)現(xiàn)的 WiFi AP 文件管理系統(tǒng)功能,通過該功能可以將設(shè)備變身為一個(gè)輕量級(jí)的文件服務(wù)器,用戶只需連接
    的頭像 發(fā)表于 10-29 15:23 ?282次閱讀
    Air8000工業(yè)引擎WiFi AP<b class='flag-5'>文件</b>管理功能<b class='flag-5'>操作</b>指南

    飛凌嵌入式ElfBoard-系統(tǒng)應(yīng)用編程之文件I/O

    ,在必要時(shí)再去通過系統(tǒng)調(diào)用讀寫實(shí)際文件,從而減少系統(tǒng)調(diào)用次數(shù),避免系統(tǒng)資源的浪費(fèi)。緩沖分有三類:全緩沖:操作的數(shù)據(jù)會(huì)存儲(chǔ)到緩沖區(qū),在緩沖區(qū)填滿后再進(jìn)行對(duì)實(shí)際
    發(fā)表于 10-24 08:57

    Java 在物聯(lián)網(wǎng)與嵌入式系統(tǒng)的應(yīng)用前景與挑戰(zhàn)

    的生態(tài)系統(tǒng)和強(qiáng)大的社區(qū)支持,Java 在智能家居、工業(yè)控制、可穿戴設(shè)備等場(chǎng)景展現(xiàn)出獨(dú)特優(yōu)勢(shì)。本文將探討 Java 在嵌入式與物聯(lián)網(wǎng)的應(yīng)用價(jià)值、技術(shù)特點(diǎn)以及未來發(fā)展趨勢(shì)。 一、
    的頭像 發(fā)表于 09-04 14:49 ?998次閱讀

    ESP32驅(qū)動(dòng)SPIFFS進(jìn)行文件操作

    本篇文章介紹如何在ESP32開發(fā)板上使用SPIFFS(SPI Flash File System)進(jìn)行文件操作??聪氯绾纬跏蓟疭PIFFS文件系統(tǒng)、讀取文件、列出
    的頭像 發(fā)表于 08-05 18:11 ?4270次閱讀
    ESP32驅(qū)動(dòng)SPIFFS進(jìn)行<b class='flag-5'>文件</b><b class='flag-5'>操作</b>

    PCB的Gerber文件是什么

    Gerber 文件是用于電子設(shè)計(jì)自動(dòng)化(EDA),尤其是在印刷電路板(PCB)設(shè)計(jì)和制造過程,傳遞電路圖層、焊盤、走線、元件布局等信息的標(biāo)準(zhǔn)格式。它在PCB制造的各個(gè)環(huán)節(jié)扮演著至
    的頭像 發(fā)表于 08-01 09:20 ?4708次閱讀

    大文件高效傳輸不求人!Ymodem協(xié)議實(shí)戰(zhàn)示例與核心技巧揭秘

    無需復(fù)雜網(wǎng)絡(luò)環(huán)境,Ymodem協(xié)議即可實(shí)現(xiàn)可靠的大文件傳輸!通過其簡潔的通信機(jī)制(如SOH幀頭、數(shù)據(jù)分塊、ACK/NACK反饋),無論是單片機(jī)通信還是跨平臺(tái)傳輸,本文示例將演示如何快速部署,并
    的頭像 發(fā)表于 07-28 17:38 ?1155次閱讀
    <b class='flag-5'>大文件</b>高效傳輸不求人!Ymodem協(xié)議實(shí)戰(zhàn)示例與核心技巧揭秘

    深度操作系統(tǒng)deepin 25跨端協(xié)同應(yīng)用升級(jí)

    在日常使用 deepin 辦公與生活,跨設(shè)備協(xié)作的效率問題時(shí)常困擾著我們:多設(shè)備間傳輸文件依賴社交工具,速度慢且大文件受限;多臺(tái)設(shè)備辦公時(shí)頻繁切換鍵鼠,打斷思路且易出錯(cuò);跨設(shè)備共享剪貼板內(nèi)容更是繁瑣,往往需要多次中轉(zhuǎn)
    的頭像 發(fā)表于 07-15 09:51 ?1574次閱讀

    可以通過SPP協(xié)議傳輸大文件嗎?

    我正在使用 CYBT-343026 (CYW-20706 Silicon) 模塊。 我根據(jù) SPP 樣本制作了一個(gè)操作 SPP 的應(yīng)用程序。 但是,傳輸大數(shù)據(jù)時(shí)有時(shí)會(huì)丟失數(shù)據(jù)。 它從
    發(fā)表于 07-07 08:16

    ArkUI-X平臺(tái)橋接Bridge說明

    的三方庫等。 說明 平臺(tái)橋接支持ArkUI調(diào)用Android Java API和iOS Objective-C API。此外,一些平臺(tái)相關(guān)功能可直接通過已有的OpenHarmony跨平臺(tái)API實(shí)現(xiàn)
    發(fā)表于 06-19 23:12

    主流版本控制工具Git vs Perforce P4:架構(gòu)模式、性能、大文件管理及分支管理對(duì)比詳解

    Git vs Perforce P4,如何選型?架構(gòu)模式、性能、大文件管理、分支策略四大維度對(duì)比,幫你全面了解兩者的核心差異,選擇更合適你團(tuán)隊(duì)需求的版本控制系統(tǒng)。
    的頭像 發(fā)表于 06-13 14:52 ?822次閱讀
    主流版本控制工具Git vs Perforce P4:架構(gòu)模式、性能、<b class='flag-5'>大文件</b>管理及分支管理對(duì)比詳解

    HarmonyOS優(yōu)化應(yīng)用文件上傳下載慢問題性能優(yōu)化二

    參考該工程。 (三)文件上傳 對(duì)于大文件斷點(diǎn)續(xù)傳上傳,本文采用request(上傳下載)模塊的request.agent任務(wù)托管接口,可以自動(dòng)實(shí)現(xiàn)暫停繼續(xù)重試等操作,無需手動(dòng)將
    發(fā)表于 05-27 16:19

    基于RK3576開發(fā)板的INI文件操作

    ”的表達(dá)方式為[Section1 Name],以括號(hào)“[]”包圍起來,它用來表示一個(gè)段落的開始,因INI文件可能是整個(gè)項(xiàng)目共用的,所以需要使用“節(jié)”來區(qū)分不同用途的參數(shù)區(qū)?!版I”與“值”的組合表達(dá)方式為
    的頭像 發(fā)表于 05-12 14:47 ?1583次閱讀
    基于RK3576開發(fā)板的INI<b class='flag-5'>文件</b><b class='flag-5'>操作</b>

    在KaihongOS,可以使用文件管理對(duì)文件進(jìn)行基礎(chǔ)的操作

    文件操作 在KaihongOS,可以使用@ohos.file.fs (文件管理)對(duì)文件進(jìn)行基礎(chǔ)的操作
    發(fā)表于 05-08 06:39