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

java  深入理解內存映射文件原理

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

內存映射文件原理

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

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

 二者的聯(lián)系

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

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

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

二者的區(qū)別

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

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

內存映射文件的原理

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

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

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

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

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

內存映射文件的效率

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

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

傳統(tǒng)IO和內存映射效率對比.

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

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ū),用時:"+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ū),用時:"+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("內存映射文件讀取文件,用時:"+t);
    } catch (FileNotFoundException e) {

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

  }
}

運行結果

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

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

內存映射文件讀取文件,用時:11

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

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

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

相關文章

  • Android中SurfaceFlinger工作原理

    Android中SurfaceFlinger工作原理

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

    Android 動態(tài)的顯示時間

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

    Android獲取手機信息的工具類

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

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

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

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

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

    ANDROID應用程序的混淆打包分享

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

    Android開發(fā)導入項目報錯Ignoring InnerClasses attribute for an anonym

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

    Monkeyrunner 常用按鍵總結

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

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

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

    詳解Android Activity的啟動流程

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

最新評論