mmap爲什麼比read/write快(兼論buffercache和pagecache)

 首先說一下文件系統,Linux文件系統的三層結構想必大家多少都瞭解一些,每個進程中都有一個用戶文件描述符表,表項指向一個全局的文件表中的某個表項,文件表表項有一個指向內存inode的指針,每個inode唯一標識一個文件。如果同時有多個進程打開同一文件,他們的用戶文件描述符表項指向不同的文件表項,但是這些文件表項會指向同一個inode。

     此時又會引出另外一個東東:page cache。內核會爲每個文件單獨維護一個page cache,用戶進程對於文件的大多數讀寫操作會直接作用到page cache上,內核會選擇在適當的時候將page cache中的內容寫到磁盤上(當然我們可以手工fsync控制回寫),這樣可以大大減少磁盤的訪問次數,從而提高性能。Page cache是linux內核文件訪問過程中很重要的數據結構,page cache中會保存用戶進程訪問過得該文件的內容,這些內容以頁爲單位保存在內存中,當用戶需要訪問文件中的某個偏移量上的數據時,內核會以偏移量爲索引,找到相應的內存頁,如果該頁沒有讀入內存,則需要訪問磁盤讀取數據。爲了提高頁得查詢速度同時節省page cache數據結構佔用的內存,linux內核使用樹來保存page cache中的頁。

     在瞭解了以上的基礎之後,我們就來比較一下mmap和read/write的區別,先說一下read/write系統調用,read/write系統調用會有以下的操作:

  1. 訪問文件,這涉及到用戶態到內核態的轉換
  2. 讀取硬盤文件中的對應數據,內核會採用預讀的方式,比如我們需要訪問100字節,內核實際會將按照4KB(內存頁的大小)存儲在page cache中
  3. 將read中需要的數據,從page cache中拷貝到用戶緩衝區中

    整個過程還是比較艱辛的,基本上涉及到用戶內核態的切換,還有就是數據拷貝接下來繼續說mmap吧,mmap系統調用是將硬盤文件映射到用內存中,說的底層一些是將page cache中的頁直接映射到用戶進程地址空間中,從而進程可以直接訪問自身地址空間的虛擬地址來訪問page cache中的頁,這樣會並涉及page cache到用戶緩衝區之間的拷貝,mmap系統調用與read/write調用的區別在於:

  1. mmap只需要一次系統調用,後續操作不需要系統調用
  2. 訪問的數據不需要在page cache和用戶緩衝區之間拷貝

     從上所述,當頻繁對一個文件進行讀取操作時,mmap會比read高效一些。

     最後再說一下page cache的話題,從上面所說我們從磁盤文件中讀取的內容都會存在page cache中,但當我們關閉這個文件時,page cache中內容會立馬釋放掉嗎?答案是否,磁盤的讀取速度比內存慢太多,如果能命中page cache可以顯著提升性能,萬一後續又有對這個文件的操作,系統就可以很快速的響應。當然,這些文件內容也不是一直存在page cache中的,一般只要系統有空閒物理內存,內核都會拿來當緩存使用,但當物理內存不夠用,內存會清理出部分page cache應急,這也就是告訴我們程序對於物理內存的使用能省則省,交給內核使用,作用很大。

     還有就是普通的write調用只是將數據寫到page cache中,並將其標記爲dirty就返回了,磁盤I/O通常不會立即執行,這樣做的好處是減少磁盤的回寫次數,提供吞吐率,不足就是機器一旦意外掛掉,page cache中的數據就會丟失。一般安全性比較高的程序會在每次write之後,調用fsync立即將page cache中的內容回寫到磁盤中。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章