MappedByteBuffer

MappedByteBuffer 是Java NIO中引入的一種硬盤物理文件和內(nèi)存映射方式胀糜,當物理文件較大時观蜗,采用MappedByteBuffer咧栗,讀寫性能較高逆甜,其內(nèi)部的核心實現(xiàn)是DirectByteBuffer(JVM 堆外直接物理內(nèi)存)。

JVM 進程通過內(nèi)存映射方式加載的物理文件并不會耗費同等大小的物理內(nèi)存致板。當應用程序訪問數(shù)據(jù)時交煞,程序通過虛擬地址尋址對應的內(nèi)存頁,如果物理內(nèi)存中不存在對應頁斟或,MMU則會產(chǎn)生缺頁中斷異常素征,CPU嘗試從系統(tǒng)Swap分區(qū)中查找,如仍不存在,則會直接從硬盤中物理文件中讀取御毅。

傳統(tǒng)的基于文件流的方式讀取文件方式是系統(tǒng)指令調(diào)用根欧,文件數(shù)據(jù)首先會被讀取到進程的內(nèi)核空間的緩沖區(qū),而后復制到進程的用戶空間端蛆,這個過程中存在兩次數(shù)據(jù)拷貝咽块;而內(nèi)存映射方式讀取文件的方式,也是系統(tǒng)指令調(diào)用欺税,在產(chǎn)生缺頁中斷后侈沪,CPU直接從磁盤文件load數(shù)據(jù)到進程的用戶空間,只有一次數(shù)據(jù)拷貝晚凿。

FileChannel提供了map方法把磁盤文件映射到虛擬內(nèi)存亭罪,通常情況可以映射整個文件,如果文件比較大歼秽,可以進行分段映射应役。

內(nèi)存映像文件訪問的方式,共三種:

a) MapMode.READ_ONLY:只讀燥筷,試圖修改得到的緩沖區(qū)將導致拋出異常箩祥。? ? b) MapMode.READ_WRITE:讀/寫,對得到的緩沖區(qū)的更改最終將寫入文件肆氓;但該更改對映射到同一文件的其他程序不一定是可見的袍祖。? ? c) MapMode.PRIVATE:私用,可讀可寫,但是修改的內(nèi)容不會寫入文件谢揪,只是buffer自身的改變蕉陋。

MappedByteBuffer在處理大文件時的確性能很高,但也存在一些問題拨扶,其所對應的內(nèi)存使用的是JVM堆外內(nèi)存凳鬓,JVM young gc和CMS gc并不能觸發(fā)回收MappedByteBuffer對應的內(nèi)存,只有full gc(stop the world的方式)可以使其回收內(nèi)存患民,堆外直接內(nèi)存會根據(jù)自己的情況(當需要新分配直接內(nèi)存時缩举,如果所剩堆外內(nèi)存空間不夠,第一次產(chǎn)生OutOfMemoryError時)來觸發(fā) System.gc()匹颤,此處有坑仅孩,若JVM配置了參數(shù)-XX:DisableExplicitGC,System.gc()將不會觸發(fā)full gc惋嚎,最終導致內(nèi)存泄漏杠氢。而且觸發(fā)其內(nèi)存回收的時間點是不確定的站刑。Java api文檔中標注:

在應用程序頻繁使用堆外內(nèi)存時另伍,還可以通過-XX:MaxDirectMemorySize來指定最大的堆外內(nèi)存大小,當使用達到了閾值的時候?qū)⒄{(diào)用System.gc來做一次full gc,以此來回收掉游離狀態(tài)的堆外內(nèi)存摆尝。

因此温艇,在使用堆外內(nèi)存高性能的福利的同時,及時的回收掉廢棄掉的內(nèi)存是十分關鍵的堕汞。

性能分析

從代碼層面上看勺爱,從硬盤上將文件讀入內(nèi)存,都要經(jīng)過文件系統(tǒng)進行數(shù)據(jù)拷貝讯检,并且數(shù)據(jù)拷貝操作是由文件系統(tǒng)和硬件驅(qū)動實現(xiàn)的琐鲁,理論上來說,拷貝數(shù)據(jù)的效率是一樣的人灼。

但是通過內(nèi)存映射的方法訪問硬盤上的文件围段,效率要比read和write系統(tǒng)調(diào)用高,這是為什么投放?

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

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

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

拷貝視頻代碼舉例:

機器配置: 內(nèi)存8G? ?CPU? 4核(i5-3210M)? ?

第一種方式:

long start = System.currentTimeMillis();

FileInputStream fis =new FileInputStream("d:\\追龍2.mp4");

FileChannel in = fis.getChannel();

FileOutputStream fos =new FileOutputStream("e:\\t.mp4");

FileChannel out = fos.getChannel();

out.transferFrom(in,0,in.size());

fis.close();

fos.close();

in.close();

out.close();

log.info(" 消耗時間:{} 秒",(System.currentTimeMillis()-start)/1000);

1.28G 大約消耗28秒時間

第二種方式:

long start = System.currentTimeMillis();

FileChannel inChannel = FileChannel.open(Paths.get("d:/追龍2.mp4"), StandardOpenOption.READ);

FileChannel outChannel = FileChannel.open(Paths.get("e:/追龍2.mp4"), StandardOpenOption.WRITE, StandardOpenOption.READ, StandardOpenOption.CREATE);

//內(nèi)存映射文件

MappedByteBuffer inMappedBuf = inChannel.map(FileChannel.MapMode.READ_ONLY,0, inChannel.size());

MappedByteBuffer outMappedBuf = outChannel.map(FileChannel.MapMode.READ_WRITE,0, inChannel.size());

byte[] dst =new byte[1024];

inMappedBuf.get(dst);

outMappedBuf.put(dst);

inMappedBuf.force();

outMappedBuf.force();

inChannel.close();

outChannel.close();

long end = System.currentTimeMillis();

log.info("拷貝文件消耗時間{}",(end-start)/1000);

同樣1.28G 究反,消耗時時間不到1秒? ?

但是 寻定,第二種方式,拷貝的視頻文件精耐,不能播放狼速,不知道什么因素,如果有知道解決方案的卦停,麻煩給我留言一下或者email 80692072@qq.com? 謝謝向胡。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市惊完,隨后出現(xiàn)的幾起案子僵芹,更是在濱河造成了極大的恐慌,老刑警劉巖小槐,帶你破解...
    沈念sama閱讀 212,599評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拇派,死亡現(xiàn)場離奇詭異荷辕,居然都是意外死亡,警方通過查閱死者的電腦和手機件豌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,629評論 3 385
  • 文/潘曉璐 我一進店門疮方,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人茧彤,你說我怎么就攤上這事骡显。” “怎么了曾掂?”我有些...
    開封第一講書人閱讀 158,084評論 0 348
  • 文/不壞的土叔 我叫張陵惫谤,是天一觀的道長。 經(jīng)常有香客問我珠洗,道長石挂,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,708評論 1 284
  • 正文 為了忘掉前任险污,我火速辦了婚禮痹愚,結果婚禮上,老公的妹妹穿的比我還像新娘蛔糯。我一直安慰自己拯腮,他們只是感情好,可當我...
    茶點故事閱讀 65,813評論 6 386
  • 文/花漫 我一把揭開白布蚁飒。 她就那樣靜靜地躺著动壤,像睡著了一般。 火紅的嫁衣襯著肌膚如雪淮逻。 梳的紋絲不亂的頭發(fā)上琼懊,一...
    開封第一講書人閱讀 50,021評論 1 291
  • 那天,我揣著相機與錄音爬早,去河邊找鬼哼丈。 笑死,一個胖子當著我的面吹牛筛严,可吹牛的內(nèi)容都是我干的醉旦。 我是一名探鬼主播,決...
    沈念sama閱讀 39,120評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼桨啃,長吁一口氣:“原來是場噩夢啊……” “哼车胡!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起照瘾,我...
    開封第一講書人閱讀 37,866評論 0 268
  • 序言:老撾萬榮一對情侶失蹤匈棘,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后析命,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體主卫,經(jīng)...
    沈念sama閱讀 44,308評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡逃默,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,633評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了队秩。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片笑旺。...
    茶點故事閱讀 38,768評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡昼浦,死狀恐怖馍资,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情关噪,我是刑警寧澤鸟蟹,帶...
    沈念sama閱讀 34,461評論 4 333
  • 正文 年R本政府宣布,位于F島的核電站使兔,受9級特大地震影響建钥,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜虐沥,卻給世界環(huán)境...
    茶點故事閱讀 40,094評論 3 317
  • 文/蒙蒙 一熊经、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧欲险,春花似錦镐依、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,850評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至喜每,卻和暖如春务唐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背带兜。 一陣腳步聲響...
    開封第一講書人閱讀 32,082評論 1 267
  • 我被黑心中介騙來泰國打工枫笛, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人刚照。 一個月前我還...
    沈念sama閱讀 46,571評論 2 362
  • 正文 我出身青樓崇堰,卻偏偏與公主長得像,于是被迫代替她去往敵國和親涩咖。 傳聞我的和親對象是個殘疾皇子海诲,可洞房花燭夜當晚...
    茶點故事閱讀 43,666評論 2 350

推薦閱讀更多精彩內(nèi)容