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

java  深入理解內(nèi)存映射文件原理

 更新時(shí)間:2016年11月30日 15:36:19   作者:楊龍飛的博客  
這篇文章主要介紹了java 深入理解內(nèi)存映射文件原理的相關(guān)資料,虛擬內(nèi)存與內(nèi)存映射文件的區(qū)別與聯(lián)系,內(nèi)存映射文件的原理和效率,需要的朋友可以參考下

內(nèi)存映射文件原理

首先說說這篇文章要解決什么問題?
1.虛擬內(nèi)存與內(nèi)存映射文件的區(qū)別與聯(lián)系.
2.內(nèi)存映射文件的原理.
3.內(nèi)存映射文件的效率.
4.傳統(tǒng)IO和內(nèi)存映射效率對(duì)比.

虛擬內(nèi)存與內(nèi)存映射文件的區(qū)別與聯(lián)系

 二者的聯(lián)系

虛擬內(nèi)存和內(nèi)存映射文件都是將一部分內(nèi)容加載到,另一部分放在磁盤上的一種機(jī)制,二者都是應(yīng)用程序動(dòng)態(tài)性的基礎(chǔ),由于二者的虛擬性,對(duì)于用戶都是透明的.

虛擬內(nèi)存其實(shí)就是硬盤的一部分,是計(jì)算機(jī)RAM與硬盤的數(shù)據(jù)交換區(qū),因?yàn)閷?shí)際的物理內(nèi)存可能遠(yuǎn)小于進(jìn)程的地址空間,這就需要把內(nèi)存中暫時(shí)不用到的數(shù)據(jù)放到硬盤上一個(gè)特殊的地方,當(dāng)請(qǐng)求的數(shù)據(jù)不在內(nèi)存中時(shí),系統(tǒng)產(chǎn)生卻頁中斷,內(nèi)存管理器便將對(duì)應(yīng)的內(nèi)存頁重新從硬盤調(diào)入物理內(nèi)存。

內(nèi)存映射文件是由一個(gè)文件到一塊內(nèi)存的映射,使應(yīng)用程序可以通過內(nèi)存指針對(duì)磁盤上的文件進(jìn)行訪問,其過程就如同對(duì)加載了文件的內(nèi)存的訪問,因此內(nèi)存文件映射非常適合于用來管理大文件。

二者的區(qū)別

1.虛擬內(nèi)存使用硬盤只能是頁面文件,而內(nèi)存映射使用的磁盤部分可以是任何磁盤文件.

2.二者的架構(gòu)不同,或者是說應(yīng)用的場(chǎng)景不同,虛擬內(nèi)存是架構(gòu)在物理內(nèi)存之上,其引入是因?yàn)閷?shí)際的物理內(nèi)存運(yùn)行程序所需的空間,即使現(xiàn)在計(jì)算機(jī)中的物理內(nèi)存越來越大,程序的尺寸也在增長(zhǎng)。將所有運(yùn)行著的程序全部加載到內(nèi)存中不經(jīng)濟(jì)也非常不現(xiàn)實(shí)。內(nèi)存映射文件架構(gòu)在程序的地址空間之上,32位機(jī)地址空間只有4G,而某些大文件的尺寸可要要遠(yuǎn)超出這個(gè)值,因此,用地址空間中的某段應(yīng)用文件中的一部分可解決處理大文件的問題,在32中,使用內(nèi)存映射文件可以處理2的64次(64EB)大小的文件.原因內(nèi)存映射文件,除了處理大文件,還可用作進(jìn)程間通信。

內(nèi)存映射文件的原理

“映射”就是建立一種對(duì)應(yīng)關(guān)系,在這里主要是指硬盤上文件的位置與進(jìn)程邏輯地址空間中一塊相同區(qū)域之間一一對(duì)應(yīng),這種關(guān)系純屬是邏輯上的概念,物理上是不存在的,原因是進(jìn)程的邏輯地址空間本身就是不存在的,在內(nèi)存映射過程中,并沒有實(shí)際的數(shù)據(jù)拷貝,文件沒有被載入內(nèi)存,只是邏輯上放入了內(nèi)存,具體到代碼,就是建立并初始化了相關(guān)的數(shù)據(jù)結(jié)構(gòu),這個(gè)過程有系統(tǒng)調(diào)用mmap()實(shí)現(xiàn),所以映射的效率很高.

這里寫圖片描述
                     內(nèi)存映射原理
上面說到建立內(nèi)存映射沒有進(jìn)行實(shí)際的數(shù)據(jù)拷貝,那么進(jìn)行進(jìn)程又怎么能最終通過內(nèi)存操作訪問到硬盤上的文件呢?
看上圖:

1.調(diào)用mmap(),相當(dāng)于要給進(jìn)行內(nèi)存映射的文件分配了虛擬內(nèi)存,它會(huì)返回一個(gè)指針ptr,這個(gè)ptr所指向的是一個(gè)邏輯地址,要操作其中的數(shù)據(jù),必須通過MMU將邏輯地址轉(zhuǎn)換成物理地址,如圖1中過程2所示。

2.建立內(nèi)存映射并沒有實(shí)際拷貝數(shù)據(jù),這時(shí),MMU在地址映射表中是無法找到與ptr相對(duì)應(yīng)的物理地址的,也就是MMU失敗,將產(chǎn)生一個(gè)缺頁中斷,缺 頁中斷的中斷響應(yīng)函數(shù)會(huì)在swap中尋找相對(duì)應(yīng)的頁面,如果找不到(也就是該文件從來沒有被讀入內(nèi)存的情況),則會(huì)通過mmap()建立的映射關(guān)系,從硬 盤上將文件讀取到物理內(nèi)存中,如圖1中過程3所示。

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

內(nèi)存映射文件的效率

了解過內(nèi)存映射文件都知道,它比傳統(tǒng)的IO讀寫數(shù)據(jù)快很多,那么,它為什么會(huì)這么快,從代碼層面上來看,從硬盤上將文件讀入內(nèi)存,都是要經(jīng)過數(shù)據(jù)拷貝,并且數(shù)據(jù)拷貝操作是由文件系統(tǒng)和硬件驅(qū)動(dòng)實(shí)現(xiàn)的,理論上來說,拷貝數(shù)據(jù)的效率是一 樣的。其實(shí),原因是read()是系統(tǒng)調(diào)用,其中進(jìn)行了數(shù)據(jù) 拷貝,它首先將文件內(nèi)容從硬盤拷貝到內(nèi)核空間的一個(gè)緩沖區(qū),如圖2中過程1,然后再將這些數(shù)據(jù)拷貝到用戶空間,如圖2中過程2,在這個(gè)過程中,實(shí)際上完成 了兩次數(shù)據(jù)拷貝 ;而mmap()也是系統(tǒng)調(diào)用,如前所述,mmap()中沒有進(jìn)行數(shù)據(jù)拷貝,真正的數(shù)據(jù)拷貝是在缺頁中斷處理時(shí)進(jìn)行的,由于mmap()將文件直接映射到用戶空間,所以中斷處理函數(shù)根據(jù)這個(gè)映射關(guān)系,直接將文件從硬盤拷貝到用戶空間,只進(jìn)行了 一次數(shù)據(jù)拷貝 。因此,內(nèi)存映射的效率要比read/write效率高。
這里寫圖片描述

read系統(tǒng)調(diào)用原理

傳統(tǒng)IO和內(nèi)存映射效率對(duì)比.

在這里,使用java傳統(tǒng)的IO,加緩沖區(qū)的IO,內(nèi)存映射分別讀取10M數(shù)據(jù).用時(shí)如下:

public class MapBufDelete {
  public static void main(String[] args) {
    try {
      FileInputStream fis=new FileInputStream("./largeFile.txt");
      int sum=0;
      int n;
      long t1=System.currentTimeMillis();
      try {
        while((n=fis.read())>=0){
          // 數(shù)據(jù)處理
        }
      } catch (IOException e) {
        e.printStackTrace();
      }
      long t=System.currentTimeMillis()-t1;
      System.out.println("傳統(tǒng)IOread文件,不使用緩沖區(qū),用時(shí):"+t);
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    }

    try {
      FileInputStream fis=new FileInputStream("./largeFile.txt");
      BufferedInputStream bis=new BufferedInputStream(fis);
      int sum=0;
      int n;
      long t1=System.currentTimeMillis();
      try {
        while((n=bis.read())>=0){
         // 數(shù)據(jù)處理
        }
      } catch (IOException e) {

        e.printStackTrace();
      }
      long t=System.currentTimeMillis()-t1;
      System.out.println("傳統(tǒng)IOread文件,使用緩沖區(qū),用時(shí):"+t);
    } catch (FileNotFoundException e) {
      e.printStackTrace();
    }

    MappedByteBuffer buffer=null;
    try {
      buffer=new RandomAccessFile("./largeFile.txt","rw").getChannel().map(FileChannel.MapMode.READ_WRITE, 0, 1253244);
      int sum=0;
      int n;
      long t1=System.currentTimeMillis();
      for(int i=0;i<1024*1024*10;i++){
        // 數(shù)據(jù)處理
      }
      long t=System.currentTimeMillis()-t1;
      System.out.println("內(nèi)存映射文件讀取文件,用時(shí):"+t);
    } catch (FileNotFoundException e) {

      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }finally {
    }

  }
}

運(yùn)行結(jié)果

傳統(tǒng)IOread文件,不使用緩沖區(qū),用時(shí):4739

傳統(tǒng)IOread文件,使用緩沖區(qū),用時(shí):59

內(nèi)存映射文件讀取文件,用時(shí):11

最后,解釋一下,為什么使用緩沖區(qū)讀取文件會(huì)比不使用快:

原因是每次進(jìn)行IO操作,都要從用戶態(tài)陷入內(nèi)核態(tài),由內(nèi)核把數(shù)據(jù)從磁盤中讀到內(nèi)核緩沖區(qū),再由內(nèi)核緩沖區(qū)到用戶緩沖區(qū),如果沒有buffer,讀取都需要從用戶態(tài)到內(nèi)核態(tài)切換,而這種切換很耗時(shí),所以,采用預(yù)讀,減少IO次數(shù),如果有buffer,根據(jù)局部性原理,就會(huì)一次多讀數(shù)據(jù),放到緩沖區(qū)中,減少了IO次數(shù).

感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!

相關(guān)文章

  • Android中SurfaceFlinger工作原理

    Android中SurfaceFlinger工作原理

    這篇文章介紹了Android中SurfaceFlinger的工作原理,對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-12-12
  • Android 動(dòng)態(tài)的顯示時(shí)間

    Android 動(dòng)態(tài)的顯示時(shí)間

    本文給大家分享一段代碼實(shí)現(xiàn)android動(dòng)態(tài)顯示時(shí)間,代碼簡(jiǎn)單易懂,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下吧
    2016-12-12
  • Android獲取手機(jī)信息的工具類

    Android獲取手機(jī)信息的工具類

    這篇文章主要為大家詳細(xì)介紹了Android獲取手機(jī)信息的工具類,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-09-09
  • Android系統(tǒng)對(duì)話框使用詳解(最詳細(xì))

    Android系統(tǒng)對(duì)話框使用詳解(最詳細(xì))

    這篇文章主要介紹了Android系統(tǒng)對(duì)話框使用詳解(最詳細(xì)),需要的朋友可以參考下
    2017-10-10
  • Android中去掉標(biāo)題欄的幾種方法(三種)

    Android中去掉標(biāo)題欄的幾種方法(三種)

    本文給大家?guī)砹巳Nandroid去掉標(biāo)題欄的方法,都非常不錯(cuò),對(duì)android 去掉標(biāo)題欄的方法感興趣的朋友一起通過本文學(xué)習(xí)吧
    2016-08-08
  • ANDROID應(yīng)用程序的混淆打包分享

    ANDROID應(yīng)用程序的混淆打包分享

    這篇文章主要介紹了ANDROID應(yīng)用程序的混淆打包,有需要的朋友可以參考一下
    2014-01-01
  • Android開發(fā)導(dǎo)入項(xiàng)目報(bào)錯(cuò)Ignoring InnerClasses attribute for an anonymous inner class的解決辦法

    Android開發(fā)導(dǎo)入項(xiàng)目報(bào)錯(cuò)Ignoring InnerClasses attribute for an anonym

    今天小編就為大家分享一篇關(guān)于Android開發(fā)導(dǎo)入項(xiàng)目報(bào)錯(cuò)Ignoring InnerClasses attribute for an anonymous inner class的解決辦法,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2018-12-12
  • Monkeyrunner 常用按鍵總結(jié)

    Monkeyrunner 常用按鍵總結(jié)

    這篇文章主要介紹了Monkeyrunner 常用按鍵總結(jié)的相關(guān)資料,這里對(duì)Monkeyrunner 按鍵的功能進(jìn)行詳細(xì)說明,需要的朋友可以參考下
    2016-11-11
  • Android中的build.gradle文件深入講解

    Android中的build.gradle文件深入講解

    這篇文章主要給大家介紹了關(guān)于Android中build.gradle文件的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-10-10
  • 詳解Android Activity的啟動(dòng)流程

    詳解Android Activity的啟動(dòng)流程

    這篇文章主要介紹了詳解Android Activity的啟動(dòng)流程,幫助大家更好的理解和學(xué)習(xí)使用Android,感興趣的朋友可以了解下
    2021-03-03

最新評(píng)論