精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

程序崩潰時,mmap映射的文件會怎樣?

存儲 數(shù)據管理
當程序崩潰這一意外降臨,mmap映射的文件瞬間陷入未知之境。是能維持原狀,還是會數(shù)據丟失、損壞,又或是引發(fā)其他復雜問題?

在程序的復雜運行機制中,mmap 作為一種內存映射文件的關鍵方法,發(fā)揮著獨特作用。它將文件或其他對象映射到進程的地址空間,讓進程能以指針方式讀寫操作對應內存區(qū)域,系統(tǒng)會自動將臟頁面回寫至文件磁盤,極大簡化了文件操作流程。然而,程序運行并非總是一帆風順,崩潰情況時有發(fā)生。

當程序崩潰這一意外降臨,mmap映射的文件瞬間陷入未知之境。是能維持原狀,還是會數(shù)據丟失、損壞,又或是引發(fā)其他復雜問題?這背后牽扯到操作系統(tǒng)內存管理機制、文件系統(tǒng)同步策略,以及mmap映射方式、文件打開模式等多方面因素。接下來,讓我們層層剖析,探尋程序崩潰時mmap映射文件的真實遭遇 。

一、mmap技術簡介

mmap 即 memory map,也就是內存映射。mmap 是一種內存映射文件的方法,即將一個文件或者其它對象映射到進程的地址空間,實現(xiàn)文件磁盤地址和進程虛擬地址空間中一段虛擬地址的一一對映關系。實現(xiàn)這樣的映射關系后,進程就可以采用指針的方式讀寫操作這一段內存,而系統(tǒng)會自動回寫臟頁面到對應的文件磁盤上,即完成了對文件的操作而不必再調用 read、write 等系統(tǒng)調用函數(shù)。相反,內核空間對這段區(qū)域的修改也直接反映用戶空間,從而可以實現(xiàn)不同進程間的文件共享。

如下圖所示:

圖片圖片

mmap的作用,在應用這一層,是讓你把文件的某一段,當作內存一樣來訪問。將文件映射到物理內存,將進程虛擬空間映射到那塊內存。這樣,進程不僅能像訪問內存一樣讀寫文件,多個進程映射同一文件,還能保證虛擬空間映射到同一塊物理內存,達到內存共享的作用。

mmap 是 Linux 中用處非常廣泛的一個系統(tǒng)調用,它將一個文件或者其它對象映射進內存。文件被映射到多個頁上,如果文件的大小不是所有頁的大小之和,最后一個頁不被使用的空間將會清零。mmap 必須以 PAGE_SIZE 為單位進行映射,而內存也只能以頁為單位進行映射,若要映射非 PAGE_SIZE 整數(shù)倍的地址范圍,要先進行內存對齊,強行以 PAGE_SIZE 的倍數(shù)大小進行映射。

其函數(shù)原型為:void *mmap (void start, size_t length, int prot, int flags, int fd, off_t offset);int munmap(void start, size_t length);。下面介紹一下內存映射的步驟:

  • 用 open 系統(tǒng)調用打開文件,并返回描述符 fd。
  • 用 mmap 建立內存映射,并返回映射首地址指針 start。
  • 對映射(文件)進行各種操作,如顯示(printf)、修改(sprintf)等。
  • 用 munmap (void *start, size_t length) 關閉內存映射。
  • 用 close 系統(tǒng)調用關閉文件 fd。

二、mmap工作原理

mmap函數(shù)創(chuàng)建一個新的vm_area_struct結構,并將其與文件/設備的物理地址相連。

vm_area_struct:linux使用vm_area_struct來表示一個獨立的虛擬內存區(qū)域,一個進程可以使用多個vm_area_struct來表示不用類型的虛擬內存區(qū)域(如堆,棧,代碼段,MMAP區(qū)域等)。

vm_area_struct結構中包含了區(qū)域起始地址。同時也包含了一個vm_opt指針,其內部可引出所有針對這個區(qū)域可以使用的系統(tǒng)調用函數(shù)。從而,進程可以通過vm_area_struct獲取操作這段內存區(qū)域所需的任何信息。

進程通過vma操作內存,而vma與文件/設備的物理地址相連,系統(tǒng)自動回寫臟頁面到對應的文件磁盤上(或寫入到設備地址空間),實現(xiàn)內存映射文件。

內存映射文件的原理:

首先創(chuàng)建虛擬區(qū)間并完成地址映射,此時還沒有將任何文件數(shù)據拷貝至主存。當進程發(fā)起讀寫操作時,會訪問虛擬地址空間,通過查詢頁表,發(fā)現(xiàn)這段地址不在物理頁上,因為只建立了地址映射,真正的數(shù)據還沒有拷貝到內存,因此引發(fā)缺頁異常。缺頁異常經過一系列判斷,確定無非法操作后,內核發(fā)起請求調頁過程。

最終會調用nopage函數(shù)把所缺的頁從文件在磁盤里的地址拷貝到物理內存。之后進程便可以對這片主存進行讀寫,如果寫操作修改了內容,一定時間后系統(tǒng)會自動回寫臟頁面到對應的磁盤地址,完成了寫入到文件的過程。另外,也可以調用msync()來強制同步,這樣所寫的內存就能立刻保存到文件中。

mmap內存映射的實現(xiàn)過程,總的來說可以分為三個階段:

⑴進程啟動映射過程,并在虛擬地址空間中為映射創(chuàng)建虛擬映射區(qū)域

  • 進程在用戶空間調用庫函數(shù)mmap,原型:void *mmap(void *start, size_t length, int prot, int flags, int fd, off_t offset);
  • 在當前進程的虛擬地址空間中,尋找一段空閑的滿足要求的連續(xù)的虛擬地址
  • 為此虛擬區(qū)分配一個vm_area_struct結構,接著對這個結構的各個域進行了初始化
  • 將新建的虛擬區(qū)結構(vm_area_struct)插入進程的虛擬地址區(qū)域鏈表或樹中

⑵調用內核空間的系統(tǒng)調用函數(shù)mmap(不同于用戶空間函數(shù)),實現(xiàn)文件物理地址和進程虛擬地址的一一映射關系

  • 為映射分配了新的虛擬地址區(qū)域后,通過待映射的文件指針,在文件描述符表中找到對應的文件描述符,通過文件描述符,鏈接到內核“已打開文件集”中該文件的文件結構體(struct file),每個文件結構體維護著和這個已打開文件相關各項信息。
  • 通過該文件的文件結構體,鏈接到file_operations模塊,調用內核函數(shù)mmap,其原型為:int mmap(struct file *filp, struct vm_area_struct *vma),不同于用戶空間庫函數(shù)。
  • 內核mmap函數(shù)通過虛擬文件系統(tǒng)inode模塊定位到文件磁盤物理地址。
  • 通過remap_pfn_range函數(shù)建立頁表,即實現(xiàn)了文件地址和虛擬地址區(qū)域的映射關系。此時,這片虛擬地址并沒有任何數(shù)據關聯(lián)到主存中。

⑶進程發(fā)起對這片映射空間的訪問,引發(fā)缺頁異常,實現(xiàn)文件內容到物理內存(主存)的拷貝

注:前兩個階段僅在于創(chuàng)建虛擬區(qū)間并完成地址映射,但是并沒有將任何文件數(shù)據的拷貝至主存。真正的文件讀取是當進程發(fā)起讀或寫操作時。

  • 進程的讀或寫操作訪問虛擬地址空間這一段映射地址,通過查詢頁表,發(fā)現(xiàn)這一段地址并不在物理頁面上。因為目前只建立了地址映射,真正的硬盤數(shù)據還沒有拷貝到內存中,因此引發(fā)缺頁異常。
  • 缺頁異常進行一系列判斷,確定無非法操作后,內核發(fā)起請求調頁過程。
  • 調頁過程先在交換緩存空間(swap cache)中尋找需要訪問的內存頁,如果沒有則調用nopage函數(shù)把所缺的頁從磁盤裝入到主存中。
  • 之后進程即可對這片主存進行讀或者寫的操作,如果寫操作改變了其內容,一定時間后系統(tǒng)會自動回寫臟頁面到對應磁盤地址,也即完成了寫入到文件的過程。

注:修改過的臟頁面并不會立即更新回文件中,而是有一段時間的延遲,可以調用msync()來強制同步, 這樣所寫的內容就能立即保存到文件里了。

三、mmap的 I/O模型

mmap 也是一種零拷貝技術,其 I/O 模型如下圖所示:、

圖片圖片

#include <sys/mman.h>
void *mmap(

void *start,
size_t length,
int prot,
int flags,
int fd, off_t offset
)

圖片圖片

mmap 技術有如下特點:

  • 利用 DMA 技術來取代 CPU 來在內存與其他組件之間的數(shù)據拷貝,例如從磁盤到內存,從內存到網卡;
  • 用戶空間的 mmap file 使用虛擬內存,實際上并不占據物理內存,只有在內核空間的 kernel buffer cache 才占據實際的物理內存;
  • mmap() 函數(shù)需要配合 write() 系統(tǒng)調動進行配合操作,這與 sendfile() 函數(shù)有所不同,后者一次性代替了 read() 以及 write();因此 mmap 也至少需要 4 次上下文切換;
  • mmap 僅僅能夠避免內核空間到用戶空間的全程 CPU 負責的數(shù)據拷貝,但是內核空間內部還是需要全程 CPU 負責的數(shù)據拷貝;

利用 mmap() 替換 read(),配合 write() 調用的整個流程如下:

  • 用戶進程調用 mmap(),從用戶態(tài)陷入內核態(tài),將內核緩沖區(qū)映射到用戶緩存區(qū);
  • DMA 控制器將數(shù)據從硬盤拷貝到內核緩沖區(qū)(可見其使用了 Page Cache 機制);
  • mmap() 返回,上下文從內核態(tài)切換回用戶態(tài);
  • 用戶進程調用 write(),嘗試把文件數(shù)據寫到內核里的套接字緩沖區(qū),再次陷入內核態(tài);
  • CPU 將內核緩沖區(qū)中的數(shù)據拷貝到的套接字緩沖區(qū);
  • DMA 控制器將數(shù)據從套接字緩沖區(qū)拷貝到網卡完成數(shù)據傳輸;
  • write() 返回,上下文從內核態(tài)切換回用戶態(tài)。

通過mmap實現(xiàn)的零拷貝I/O進行了4次用戶空間與內核空間的上下文切換,以及3次數(shù)據拷貝;其中3次數(shù)據拷貝中包括了2次DMA拷貝和1次CPU拷貝

3.1mmap與常規(guī)文件操作的區(qū)別

常規(guī)文件操作在進行讀寫時,為了提高效率和保護磁盤,采用了頁緩存機制。讀文件時,首先將文件頁從磁盤拷貝到頁緩存中,由于頁緩存處于內核空間,用戶進程無法直接尋址,所以還需要將頁緩存中的數(shù)據頁再次拷貝到內存對應的用戶空間中。寫操作也類似,待寫入的 buffer 在內核空間不能直接訪問,必須先拷貝至內核空間對應的主存,再寫回磁盤,同樣需要兩次數(shù)據拷貝。

而 mmap 在創(chuàng)建虛擬內存區(qū)域和建立映射時無文件拷貝操作。當后續(xù)訪問數(shù)據引發(fā)缺頁異常時,僅需一次數(shù)據拷貝,就可以從磁盤中將數(shù)據傳入內存的用戶空間中,供進程使用。

例如,在使用 mmap 操作文件中,以實現(xiàn)進程間通信為例,多個進程可以使用 mmap 來共享內存段,通過已經建立好的映射關系,在訪問數(shù)據時只進行一次數(shù)據拷貝,實現(xiàn)進程間快速通信。

總而言之,常規(guī)文件操作需要從磁盤到頁緩存再到用戶主存的兩次數(shù)據拷貝。而 mmap 操控文件,只需要從磁盤到用戶主存的一次數(shù)據拷貝過程。mmap 的關鍵點在于實現(xiàn)了用戶空間和內核空間的數(shù)據直接交互,省去了空間不同數(shù)據不通的繁瑣過程,因此效率更高。

3.2mmap不是銀彈

mmap 不是銀彈,這意味著 mmap 也有其缺陷,在相關場景下的性能存在缺陷:

  • 由于 MMAP 使用時必須實現(xiàn)指定好內存映射的大小,因此 mmap 并不適合變長文件;
  • 如果更新文件的操作很多,mmap 避免兩態(tài)拷貝的優(yōu)勢就被攤還,最終還是落在了大量的臟頁回寫及由此引發(fā)的隨機 I/O 上,所以在隨機寫很多的情況下,mmap 方式在效率上不一定會比帶緩沖區(qū)的一般寫快;
  • 讀/寫小文件(例如 16K 以下的文件),mmap 與通過 read 系統(tǒng)調用相比有著更高的開銷與延遲;同時 mmap 的刷盤由系統(tǒng)全權控制,但是在小數(shù)據量的情況下由應用本身手動控制更好;
  • mmap 受限于操作系統(tǒng)內存大小:例如在 32-bits 的操作系統(tǒng)上,虛擬內存總大小也就 2GB,但由于 mmap 必須要在內存中找到一塊連續(xù)的地址塊,此時你就無法對 4GB 大小的文件完全進行 mmap,在這種情況下你必須分多塊分別進行 mmap,但是此時地址內存地址已經不再連續(xù),使用 mmap 的意義大打折扣,而且引入了額外的復雜性;

四、mmap技術的優(yōu)勢

4.1簡化用戶進程編程

在用戶空間看來,通過 mmap 機制以后,磁盤上的文件仿佛直接就在內存中,把訪問磁盤文件簡化為按地址訪問內存。這樣一來,應用程序自然不需要使用文件系統(tǒng)的 write(寫入)、read(讀取)、fsync(同步)等系統(tǒng)調用,因為現(xiàn)在只要面向內存的虛擬空間進行開發(fā)。但是,這并不意味著我們不再需要進行這些系統(tǒng)調用,而是說這些系統(tǒng)調用由操作系統(tǒng)在 mmap 機制的內部封裝好了。

①基于缺頁異常的懶加載

出于節(jié)約物理內存以及 mmap 方法快速返回的目的,mmap 映射采用懶加載機制。具體來說,通過 mmap 申請 1000G 內存可能僅僅占用了 100MB 的虛擬內存空間,甚至沒有分配實際的物理內存空間。當你訪問相關內存地址時,才會進行真正的 write、read 等系統(tǒng)調用。CPU 會通過陷入缺頁異常的方式來將磁盤上的數(shù)據加載到物理內存中,此時才會發(fā)生真正的物理內存分配。

②數(shù)據一致性由 OS 確保

當發(fā)生數(shù)據修改時,內存出現(xiàn)臟頁,與磁盤文件出現(xiàn)不一致。mmap 機制下由操作系統(tǒng)自動完成內存數(shù)據落盤(臟頁回刷),用戶進程通常并不需要手動管理數(shù)據落盤。

4.2避免只讀操作時的 swap 操作

虛擬內存帶來了種種好處,但是一個最大的問題在于所有進程的虛擬內存大小總和可能大于物理內存總大小,因此當操作系統(tǒng)物理內存不夠用時,就會把一部分內存 swap 到磁盤上。

在 mmap 下,如果虛擬空間沒有發(fā)生寫操作,那么由于通過 mmap 操作得到的內存數(shù)據完全可以通過再次調用 mmap 操作映射文件得到。但是,通過其他方式分配的內存,在沒有發(fā)生寫操作的情況下,操作系統(tǒng)并不知道如何簡單地從現(xiàn)有文件中(除非其重新執(zhí)行一遍應用程序,但是代價很大)恢復內存數(shù)據,因此必須將內存 swap 到磁盤上。

高效的 I/O 操作方式,尤其在處理大文件或頻繁訪問文件內容時性能優(yōu)勢明顯。

在 Linux 系統(tǒng)中,mmap 是一種非常高效的 I/O 操作方式。當處理大文件或需要頻繁訪問文件內容時,能夠帶來很大的性能優(yōu)勢。例如,當一個進程通過 mmap 映射一個文件時,操作系統(tǒng)會在進程的地址空間中創(chuàng)建一個映射區(qū)域,使得進程可以直接訪問這個文件而不需要進行 read 或 write 系統(tǒng)調用。這種直接內存訪問的方式,避免了傳統(tǒng)文件訪問中多次系統(tǒng)調用和數(shù)據復制的開銷,提高了文件訪問的效率。

減少 CPU 和內存開銷,具有更好的內核態(tài)數(shù)據傳輸效率。

mmap 技術可以減少 CPU 和內存的開銷。它通過將文件或設備映射到進程的地址空間中,實現(xiàn)了直接內存訪問,避免了內核緩沖區(qū)和用戶空間緩沖區(qū)之間的數(shù)據復制。此外,mmap 還具有更好的內核態(tài)數(shù)據傳輸效率,有助于減少數(shù)據傳輸時的內存拷貝。例如,在 Kafka 中,Consumer 端對稀疏索引的操作使用了 mmap,將稀疏索引文件進行內存映射,不會招致系統(tǒng)調用以及額外的內存復制開銷,從而提高了文件讀取效率。

提升系統(tǒng)整體性能,改善用戶體驗。

合理地利用 mmap 技術,能夠提升系統(tǒng)的整體性能,改善用戶體驗。在開發(fā)應用程序時,可以考慮使用 mmap 技術來加速文件訪問、減少內存拷貝、提高數(shù)據傳輸效率等方面。例如,在處理大文件時,mmap 可以不用把全部數(shù)據都加載到內存,可以通過 MappedByteBuffer 的 position 來設置獲取數(shù)據的位置,還可以使用虛擬內存來映射超過物理內存大小的大文件。同時,mmap 也支持多進程訪問和文件的共享,多個進程可以共享同一個文件的內容,從而減少內存的使用,提高系統(tǒng)的性能。

五、mmap技術的應用場景

5.1內存映射 I/O,加速文件讀寫操作,適合處理大文件。

mmap 可以將文件直接映射到進程的虛擬地址空間,避免了傳統(tǒng)文件讀寫中的多次系統(tǒng)調用和數(shù)據拷貝。在處理大文件時,這種方式尤其有效。例如,當需要對一個大型數(shù)據文件進行頻繁的讀寫操作時,使用 mmap 可以大大提高效率。通過內存映射,進程可以像訪問內存一樣訪問文件數(shù)據,減少了磁盤 I/O 的開銷。

參考資料中提到,進程讀寫數(shù)據時,使用 mmap 進行文件映射可以減少一次拷貝操作。磁盤文件直接加載到用戶空間,進程可以通過指針直接操作文件,理論上比傳統(tǒng)的 read 和 write 操作要快。雖然在讀寫過程中可能會觸發(fā)大量中斷,但對于大文件的處理,mmap 仍然具有很大的優(yōu)勢。

5.2進程間通信,多個進程可通過共享內存實現(xiàn)快速通信。

多個進程可以通過共享內存的方式,使用 mmap 來共享內存段,實現(xiàn)進程間快速通信。例如,在父子進程或無親緣關系的進程中,都可以將自身用戶空間映射到同一個文件或匿名映射到同一片區(qū)域,從而實現(xiàn)進程間通信。

參考資料中提到,在進程間通信的場景下,可以使用 mmap 將文件映射到內存,多個進程通過對同一文件的讀寫達到進程間通信的目的。同時,共享匿名內存也可以讓相關進程共享一塊內存區(qū)域,通常用于父子進程。

5.3內存分配,匿名映射可提供比 malloc 更靈活的內存管理機制。

當需要大塊的內存,或者特定對齊要求的內存時,mmap 的匿名映射可以提供比 malloc 更靈活的內存管理機制。例如,當需要分配的內存大于一定閾值(如 128KB)時,glibc 會默認使用 mmap 代替 brk 來分配內存。

私有匿名映射最常見的用途是在 glibc 分配大塊的內存中。同時,共享匿名映射也可以讓相關進程共享一塊內存區(qū)域,為內存分配提供了更多的靈活性。

六、如何使用mmap技術

6.1mmap使用細節(jié)

使用mmap需要注意的一個關鍵點是,mmap映射區(qū)域大小必須是物理頁大小(page_size)的整倍數(shù)(32位系統(tǒng)中通常是4k字節(jié))。原因是,內存的最小粒度是頁,而進程虛擬地址空間和內存的映射也是以頁為單位。為了匹配內存的操作,mmap從磁盤到虛擬地址空間的映射也必須是頁。

內核可以跟蹤被內存映射的底層對象(文件)的大小,進程可以合法的訪問在當前文件大小以內又在內存映射區(qū)以內的那些字節(jié)。也就是說,如果文件的大小一直在擴張,只要在映射區(qū)域范圍內的數(shù)據,進程都可以合法得到,這和映射建立時文件的大小無關。

映射建立之后,即使文件關閉,映射依然存在。因為映射的是磁盤的地址,不是文件本身,和文件句柄無關。同時可用于進程間通信的有效地址空間不完全受限于被映射文件的大小,因為是按頁映射。

在上面的知識前提下,我們下面看看如果大小不是頁的整倍數(shù)的具體情況:

情形一:一個文件的大小是5000字節(jié),mmap函數(shù)從一個文件的起始位置開始,映射5000字節(jié)到虛擬內存中。

分析:因為單位物理頁面的大小是4096字節(jié),雖然被映射的文件只有5000字節(jié),但是對應到進程虛擬地址區(qū)域的大小需要滿足整頁大小,因此mmap函數(shù)執(zhí)行后,實際映射到虛擬內存區(qū)域8192個 字節(jié),5000~8191的字節(jié)部分用零填充。映射后的對應關系如下圖所示:

圖片圖片

此時:(1)讀/寫前5000個字節(jié)(0~4999),會返回操作文件內容。(2)讀字節(jié)50008191時,結果全為0。寫50008191時,進程不會報錯,但是所寫的內容不會寫入原文件中 。(3)讀/寫8192以外的磁盤部分,會返回一個SIGSECV錯誤。

情形二:一個文件的大小是5000字節(jié),mmap函數(shù)從一個文件的起始位置開始,映射15000字節(jié)到虛擬內存中,即映射大小超過了原始文件的大小。

分析:由于文件的大小是5000字節(jié),和情形一一樣,其對應的兩個物理頁。那么這兩個物理頁都是合法可以讀寫的,只是超出5000的部分不會體現(xiàn)在原文件中。由于程序要求映射15000字節(jié),而文件只占兩個物理頁,因此8192字節(jié)~15000字節(jié)都不能讀寫,操作時會返回異常。如下圖所示:

圖片圖片

此時:(1)進程可以正常讀/寫被映射的前5000字節(jié)(0~4999),寫操作的改動會在一定時間后反映在原文件中。(2)對于5000~8191字節(jié),進程可以進行讀寫過程,不會報錯。但是內容在寫入前均為0,另外,寫入后不會反映在文件中。(3)對于8192~14999字節(jié),進程不能對其進行讀寫,會報SIGBUS錯誤。(4)對于15000以外的字節(jié),進程不能對其讀寫,會引發(fā)SIGSEGV錯誤。

情形三:一個文件初始大小為0,使用mmap操作映射了10004K的大小,即1000個物理頁大約4M字節(jié)空間,mmap返回指針ptr。

分析:如果在映射建立之初,就對文件進行讀寫操作,由于文件大小為0,并沒有合法的物理頁對應,如同情形二一樣,會返回SIGBUS錯誤。但是如果,每次操作ptr讀寫前,先增加文件的大小,那么ptr在文件大小內部的操作就是合法的。例如,文件擴充4096字節(jié),ptr就能操作ptr ~ [ (char)ptr + 4095]的空間。只要文件擴充的范圍在1000個物理頁(映射范圍)內,ptr都可以對應操作相同的大小。這樣,方便隨時擴充文件空間,隨時寫入文件,不造成空間浪費。

6.2函數(shù)定義及參數(shù)解釋

在 Linux 中,mmap 函數(shù)定義如下:void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);。參數(shù)解釋如下:

  • addr:希望映射的起始地址,通常為 NULL,表示由內核決定映射的地址。
  • length:映射區(qū)域的大小(以字節(jié)為單位)。
  • prot:映射區(qū)域的保護權限,決定映射的頁面是否可讀、可寫等。常見的權限選項包括:PROT_READ(可讀)、PROT_WRITE(可寫)、PROT_EXEC(可執(zhí)行)、PROT_NONE(無權限)。
  • flags:映射的類型和行為控制。常見的標志包括:MAP_SHARED(共享映射,對該內存的修改會同步到文件)、MAP_PRIVATE(私有映射,對該內存的修改不會影響原文件,寫時拷貝)、MAP_ANONYMOUS(匿名映射,不涉及文件,通常用于分配未初始化的內存)。
  • fd:文件描述符,指向要映射的文件。如果使用匿名映射,應將 fd 設置為 -1,并且需要設置 MAP_ANONYMOUS 標志。
  • offset:文件映射的偏移量,必須是頁面大小的整數(shù)倍(通常為 4096 字節(jié))。

返回值:返回映射區(qū)域的起始地址,如果映射失敗,則返回 MAP_FAILED。

6.3mmap映射

在內存映射的過程中,并沒有實際的數(shù)據拷貝,文件沒有被載入內存,只是邏輯上被放入了內存,具體到代碼,就是建立并初始化了相關的數(shù)據結構(struct address_space),這個過程有系統(tǒng)調用mmap()實現(xiàn),所以建立內存映射的效率很高。既然建立內存映射沒有進行實際的數(shù)據拷貝,那么進程又怎么能最終直接通過內存操作訪問到硬盤上的文件呢?

那就要看內存映射之后的幾個相關的過程了。mmap()會返回一個指針ptr,它指向進程邏輯地址空間中的一個地址,這樣以后,進程無需再調用read或write對文件進行讀寫,而只需要通過ptr就能夠操作文件。但是ptr所指向的是一個邏輯地址,要操作其中的數(shù)據,必須通過MMU將邏輯地址轉換成物理地址,這個過程與內存映射無關。前面講過,建立內存映射并沒有實際拷貝數(shù)據,這時,MMU在地址映射表中是無法找到與ptr相對應的物理地址的,也就是MMU失敗,將產生一個缺頁中斷,缺頁中斷的中斷響應函數(shù)會在swap中尋找相對應的頁面,如果找不到(也就是該文件從來沒有被讀入內存的情況),則會通過mmap()建立的映射關系,從硬盤上將文件讀取到物理內存中,如圖1中過程3所示。這個過程與內存映射無關。如果在拷貝數(shù)據時,發(fā)現(xiàn)物理內存不夠用,則會通過虛擬內存機制(swap)將暫時不用的物理頁面交換到硬盤上,這個過程也與內存映射無關。

mmap內存映射的實現(xiàn)過程:

  • 進程啟動映射過程,并在虛擬地址空間中為映射創(chuàng)建虛擬映射區(qū)域
  • 調用內核空間的系統(tǒng)調用函數(shù)mmap(不同于用戶空間函數(shù)),實現(xiàn)文件物理地址和進程虛擬地址的一一映射關系
  • 進程發(fā)起對這片映射空間的訪問,引發(fā)缺頁異常,實現(xiàn)文件內容到物理內存(主存)的拷貝

適合的場景

  • 您有一個很大的文件,其內容您想要隨機訪問一個或多個時間
  • 您有一個小文件,它的內容您想要立即讀入內存并經常訪問。這種技術最適合那些大小不超過幾個虛擬內存頁的文件。(頁是地址空間的最小單位,虛擬頁和物理頁的大小是一樣的,通常為4KB。)
  • 您需要在內存中緩存文件的特定部分。文件映射消除了緩存數(shù)據的需要,這使得系統(tǒng)磁盤緩存中的其他數(shù)據空間更大 當隨機訪問一個非常大的文件時,通常最好只映射文件的一小部分。映射大文件的問題是文件會消耗活動內存。如果文件足夠大,系統(tǒng)可能會被迫將其他部分的內存分頁以加載文件。將多個文件映射到內存中會使這個問題更加復雜。

不適合的場景

  • 您希望從開始到結束的順序從頭到尾讀取一個文件
  • 這個文件有幾百兆字節(jié)或者更大。將大文件映射到內存中會快速地填充內存,并可能導致分頁,這將抵消首先映射文件的好處。對于大型順序讀取操作,禁用磁盤緩存并將文件讀入一個小內存緩沖區(qū)
  • 該文件大于可用的連續(xù)虛擬內存地址空間。對于64位應用程序來說,這不是什么問題,但是對于32位應用程序來說,這是一個問題
  • 該文件位于可移動驅動器上
  • 該文件位于網絡驅動器上

示例代碼

//
//  ViewController.m
//  TestCode
//
//  Created by zhangdasen on 2020/5/24.
//  Copyright ? 2020 zhangdasen. All rights reserved.
//

#import "ViewController.h"
#import <sys/mman.h>
#import <sys/stat.h>
@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    NSString *path = [NSHomeDirectory() stringByAppendingPathComponent:@"test.data"];
    NSLog(@"path: %@", path);
    NSString *str = @"test str2";
    [str writeToFile:path atomically:YES encoding:NSUTF8StringEncoding error:nil];

    ProcessFile(path.UTF8String);
    NSString *result = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
    NSLog(@"result:%@", result);
}


int MapFile(const char * inPathName, void ** outDataPtr, size_t * outDataLength, size_t appendSize)
{
    int outError;
    int fileDescriptor;
    struct stat statInfo;

    // Return safe values on error.
    outError = 0;
    *outDataPtr = NULL;
    *outDataLength = 0;

    // Open the file.
    fileDescriptor = open( inPathName, O_RDWR, 0 );
    if( fileDescriptor < 0 )
    {
        outError = errno;
    }
    else
    {
        // We now know the file exists. Retrieve the file size.
        if( fstat( fileDescriptor, &statInfo ) != 0 )
        {
            outError = errno;
        }
        else
        {
            ftruncate(fileDescriptor, statInfo.st_size + appendSize);
            fsync(fileDescriptor);
            *outDataPtr = mmap(NULL,
                               statInfo.st_size + appendSize,
                               PROT_READ|PROT_WRITE,
                               MAP_FILE|MAP_SHARED,
                               fileDescriptor,
                               0);
            if( *outDataPtr == MAP_FAILED )
            {
                outError = errno;
            }
            else
            {
                // On success, return the size of the mapped file.
                *outDataLength = statInfo.st_size;
            }
        }

        // Now close the file. The kernel doesn’t use our file descriptor.
        close( fileDescriptor );
    }

    return outError;
}


void ProcessFile(const char * inPathName)
{
    size_t dataLength;
    void * dataPtr;
    char *appendStr = " append_key2";
    int appendSize = (int)strlen(appendStr);
    if( MapFile(inPathName, &dataPtr, &dataLength, appendSize) == 0) {
        dataPtr = dataPtr + dataLength;
        memcpy(dataPtr, appendStr, appendSize);
        // Unmap files
        munmap(dataPtr, appendSize + dataLength);
    }
}
@end

6.5解除映射的方法

使用 mmap 后,必須調用 munmap 來解除映射,釋放分配的虛擬內存。其函數(shù)定義如下:int munmap(void *addr, size_t length);。

  • addr:要解除映射的內存區(qū)域的起始地址。
  • length:要解除映射的大小。

返回值:成功返回 0,失敗返回 -1。

⑴利用 mmap 訪問硬件,減少數(shù)據拷貝次數(shù)

mmap 可以將文件、設備等外部資源映射到內存地址空間,進程可以像訪問內存一樣訪問文件數(shù)據或硬件資源。當使用 mmap 訪問硬件時,數(shù)據可以直接從硬件設備通過 DMA 拷貝到內核緩沖區(qū),然后進程可以直接訪問這個緩沖區(qū),減少了數(shù)據拷貝的次數(shù)。例如,在嵌入式系統(tǒng)中,可以使用 mmap 將物理地址映射到用戶虛擬地址空間,實現(xiàn)對硬件設備的直接訪問。在進行數(shù)據傳輸時,避免了傳統(tǒng)方式中從內核空間到用戶空間的多次數(shù)據拷貝,提高了數(shù)據傳輸?shù)男省?/span>

⑵通過 mmap 實現(xiàn)將物理地址映射到用戶虛擬地址空間

可以通過以下步驟實現(xiàn)將物理地址映射到用戶虛擬地址空間:

  • 打開 /dev/mem 文件獲得文件描述符 dev_mem_fd。
  • 使用 mmap 函數(shù)進行映射,將物理地址映射到用戶虛擬地址空間。例如,定義一個函數(shù) dma_mmap 來實現(xiàn)這個功能,函數(shù)原型為 int dma_mmap(unsigned long addr_p, unsigned int len, unsigned char** addr_v)。在這個函數(shù)中,首先打開 /dev/mem 文件,然后使用 mmap 函數(shù)進行映射,最后返回虛擬地址。
  • 使用映射后的虛擬地址進行操作,例如讀寫硬件設備。
  • 在使用完后,調用 dma_munmap 函數(shù)解除映射,釋放資源。函數(shù)原型為 unsigned int dma_munmap(unsigned char* addr_v, unsigned long addr_p, unsigned int len)。

⑶在嵌入式系統(tǒng)中,還可以通過以下方式實現(xiàn)物理地址到用戶虛擬地址空間的映射:

  • 在驅動程序中,實現(xiàn) mmap 方法,建立虛擬地址到物理地址的頁表。例如,可以使用 remap_pfn_range 函數(shù)一次建立所有頁表,或者使用 nopage VMA 方法每次建立一個頁表。
  • 在用戶空間程序中,使用 mmap 函數(shù)進行映射,將文件描述符、映射大小、保護權限等參數(shù)傳入,獲得映射后的虛擬地址。然后可以通過這個虛擬地址對硬件設備進行操作。
責任編輯:武曉燕 來源: 深度Linux
相關推薦

2011-04-25 17:15:39

MongodbMMAP

2014-07-28 11:20:20

mmap虛擬映射Linux

2023-03-01 10:37:51

2021-11-11 05:00:02

JavaMmap內存

2010-06-02 10:42:39

Linux mysql

2011-05-27 09:19:32

Windows 7崩潰

2022-10-19 10:29:08

云原生DevOpsCloudOps

2014-02-19 16:26:26

VDI部署

2022-02-18 15:07:29

goroutinepanic協(xié)程

2013-08-20 09:48:59

2020-04-07 15:28:22

蘋果MacOS漏洞

2017-01-05 15:07:33

2025-05-08 03:33:00

Linuxperf.NET

2017-01-16 13:34:21

2022-11-24 11:09:03

自然語言處理(智能語音

2009-12-03 13:32:04

Virtuozzo捆綁

2021-11-02 06:58:52

移位負數(shù)二進制

2025-08-28 07:58:18

2013-06-03 09:34:14

崩潰程序程序算法

2014-12-31 10:02:14

Android可穿戴設備世界
點贊
收藏

51CTO技術棧公眾號

国产女人18水真多毛片18精品| 日本一道本久久| 国产aⅴ一区二区三区| 欧美女人交a| 亚洲精品99久久久久中文字幕| 欧美精品一区免费| 婷婷激情在线| 国产高清久久久| 国产91|九色| 日本黄色录像视频| 欧美美女在线直播| 欧美日韩亚洲丝袜制服| 久久99久久久久久| 成人性爱视频在线观看| 国产suv一区二区三区88区| 欧美在线观看一区二区三区| 精品国产国产综合精品| 欧美日日夜夜| 日韩一区二区三区免费看 | 99www免费人成精品| 在线观看日本视频| 欧美片第1页综合| 亚洲石原莉奈一区二区在线观看| 中文字幕人妻无码系列第三区| 午夜不卡影院| 亚洲一区影音先锋| 综合网五月天| 69av在线| 久久久久久毛片| 97超碰人人看人人 | 日韩女优av电影在线观看| 国产精彩免费视频| 久九九久频精品短视频| 天天综合天天综合色| 第九区2中文字幕| 免费在线观看黄色网| 国产日韩av一区| 蜜桃精品久久久久久久免费影院| 丰满肉肉bbwwbbww| 久久精品二区亚洲w码| 日本午夜在线亚洲.国产| 黄色激情视频在线观看| 欧美激情视频一区二区三区免费| 色婷婷**av毛片一区| 99久久久无码国产精品性| 婷婷成人影院| 亚洲精品视频网上网址在线观看| 黄色污在线观看| 红杏成人性视频免费看| 精品国产免费人成电影在线观看四季 | 久久国产精品亚洲77777| 欧美激情视频在线免费观看 欧美视频免费一| 中文字幕第二区| 日产精品一区二区| 中文字幕日韩av综合精品| 婷婷色一区二区三区| 精品国产乱码久久久| 一本色道久久88精品综合| 国产一二三四五区| 欧美色蜜桃97| 北条麻妃在线一区二区| 乱h高h女3p含苞待放| 一区二区三区四区电影| 欧美激情一区二区三区成人| 欧美日韩激情在线观看| 亚洲精品123区| 欧美一级淫片丝袜脚交| 中文字幕天堂在线| 热久久国产精品| 成人免费观看网址| 国内老熟妇对白hdxxxx| 成人精品电影在线观看| 久久精品成人一区二区三区蜜臀| 每日更新在线观看av| 欧美国产一区在线| 男人的天堂成人| 欧美人与禽性xxxxx杂性| 图片区日韩欧美亚洲| 人妻内射一区二区在线视频| 97欧美成人| 欧美精品777| 在线免费看黄色片| 国产影视精品一区二区三区| 中文字幕精品在线| 青青操视频在线播放| 99在线精品视频在线观看| 日韩暖暖在线视频| 精品国自产拍在线观看| 91在线播放网址| 一区二区三区日韩视频| 极品av在线| 欧美日本乱大交xxxxx| 亚洲国产精品狼友在线观看| 国内精品久久久久久久久电影网| 久久躁日日躁aaaaxxxx| 国产免费观看av| 免费成人av在线播放| 国产精品日韩二区| 98在线视频| 亚洲国产精品一区二区久久| 天天爽人人爽夜夜爽| 日韩中文字幕无砖| 在线播放精品一区二区三区 | 成人片在线免费看| 黄色影院在线播放| 亚洲一区二区三区小说| 黄色三级视频在线| 精品福利网址导航| 久久久精品在线观看| 中文字幕在线播| 高清国产一区二区三区| 亚洲欧美国产不卡| 自拍网站在线观看| 精品少妇一区二区三区免费观看| 亚洲毛片亚洲毛片亚洲毛片| 亚洲麻豆av| 96精品久久久久中文字幕| 青青草在线免费视频| 亚洲黄一区二区三区| 另类小说色综合| 亚洲资源网你懂的| 久久久伊人日本| 国产男男gay体育生白袜| 国产性色一区二区| 俄罗斯av网站| 凹凸成人在线| 九九久久久久99精品| 国产一区二区三区成人| 日本一区二区综合亚洲| 免费黄色福利视频| 欧美理论电影在线精品| 久久久免费精品视频| jlzzjlzz亚洲女人18| 国产精品久久精品日日| www.日本xxxx| 国产欧美日韩一区二区三区四区| 97在线视频免费看| 高清毛片aaaaaaaaa片| 亚洲精品中文在线影院| 国内自拍第二页| 欧美成人milf| 成人妇女免费播放久久久| 欧洲美女少妇精品| 欧美日韩精品电影| 国产黄a三级三级| 久久黄色级2电影| 亚洲高清123| 日本免费成人| 久久香蕉频线观| 国产草草影院ccyycom| 亚洲天堂久久久久久久| 欧美一级免费在线| 在线中文字幕亚洲| 97久久天天综合色天天综合色hd| 婷婷色在线资源| 欧美精品一区二区高清在线观看| 国产午夜激情视频| 99久久婷婷国产综合精品 | 欧美精品成人久久| 成人精品亚洲人成在线| av免费观看国产| 亚洲盗摄视频| 国产精品视频一| 国产激情视频在线| 精品久久久三级丝袜| 国产成人无码精品久在线观看| 99精品国产视频| 女人另类性混交zo| 欧美xxav| 国产精品久久国产精品| av高清不卡| 日韩网站免费观看| 国产黄色片免费观看| 黄色成人av网| 五月婷婷婷婷婷| 国产激情一区二区三区四区| 丰满少妇久久久| 精品久久精品| 亚洲自拍av在线| 国产v日韩v欧美v| 伊人成人开心激情综合网| 99热这里只有精品在线观看| 亚洲va韩国va欧美va| 中文字幕在线1| 激情五月播播久久久精品| 性一交一乱一伧国产女士spa| 亚洲精品动态| 91色琪琪电影亚洲精品久久| av色在线观看| 色综合伊人色综合网| 人妻精品一区二区三区| 欧美午夜精品久久久久久孕妇 | 欧美中文字幕一区二区三区| 天天干中文字幕| www日韩大片| 午夜激情影院在线观看| 销魂美女一区二区三区视频在线| 亚洲精品一区二区三| 韩国精品福利一区二区三区| 国产精品久久久久久久久久久久| 青草视频在线免费直播| 国产一区二区av| 免费看黄色一级视频| 欧美私模裸体表演在线观看| 国产五月天婷婷| 亚洲手机成人高清视频| 精品国产av无码| 国产91精品精华液一区二区三区| 我看黄色一级片| 国产精品久久久久久模特 | 国产欧美在线| 高清无码一区二区在线观看吞精| 欧美久久精品一级c片| 国产高清自拍一区| 97色婷婷成人综合在线观看| 日韩美女在线观看| 国产高潮在线| 色综合久久久888| 午夜视频在线观看免费视频| 亚洲乱码国产乱码精品精| 国产自产一区二区| 欧美日韩免费观看一区二区三区| 国产成人综合欧美精品久久| 亚洲午夜激情av| 麻豆精品一区二区三区视频| 国产精品卡一卡二| 日本理论中文字幕| 久久免费精品国产久精品久久久久| 亚洲国产精品狼友在线观看| 国产乱子伦一区二区三区国色天香 | 免费一区二区三区| 久久国产精品免费精品3p| 91麻豆蜜桃| 久久69av| 亚洲综合在线中文字幕| 动漫一区二区三区| 91视频国产高清| 日韩毛片网站| 国产综合福利在线| 久久影视精品| 国产综合久久久久久| 在线不卡一区| 91久久久久久| 精品成人18| 91久久精品www人人做人人爽| 我要色综合中文字幕| 91成人免费视频| 51亚洲精品| 极品日韩久久| 亚洲桃色综合影院| 日产中文字幕在线精品一区| 精品欧美激情在线观看| 亚洲毛片aa| 亚洲h色精品| av一区二区三区免费观看| 欧美精品三区| 成人网站免费观看入口| 亚洲一级在线| 欧美婷婷精品激情| 精品亚洲porn| ass极品水嫩小美女ass| 成人aaaa免费全部观看| 少妇光屁股影院| 国产精品女人毛片| 亚洲综合网在线| 午夜精品视频在线观看| 中文字幕第四页| 欧美日韩三级一区二区| a天堂在线视频| 日韩激情视频在线播放| 国产51人人成人人人人爽色哟哟| 在线观看亚洲区| 在线电影福利片| 欧美一级黑人aaaaaaa做受| 欧美精选视频一区二区| 国产日韩欧美一二三区| 99re8这里有精品热视频8在线| 九九九九精品九九九九| 美女网站一区| 一区二区精品免费视频| 亚洲成人直播| 亚洲成人天堂网| 国产黄色精品视频| 欧美熟妇精品黑人巨大一二三区| 中文字幕精品一区二区三区精品| 青青操国产视频| 色天天综合色天天久久| 国产欧美久久久| 亚洲精品一区久久久久久| 在线中文资源天堂| 欧美精品videosex性欧美| 成人精品高清在线视频| 91青青草免费观看| sdde在线播放一区二区| 18视频在线观看娇喘| 久久久久免费| 原创真实夫妻啪啪av| 国产视频一区在线播放| 九九视频免费在线观看| 欧美亚洲日本一区| 黄色aaa毛片| 色青青草原桃花久久综合| 在线天堂新版最新版在线8| 成人亲热视频网站| 欧美精品系列| 成人黄色av片| 国产一区欧美日韩| 人妻精品久久久久中文| 亚洲第一精品在线| 国产熟女精品视频| 在线观看成人黄色| 日韩理论视频| 国产福利久久精品| 久久久久美女| 少妇一级淫免费放| 91小视频在线观看| 久久免费精彩视频| 欧美放荡的少妇| 国产日本在线| 国产成人精品网站| 日韩美脚连裤袜丝袜在线| 轻点好疼好大好爽视频| 狠狠色狠狠色综合| 国产视频123区| 色婷婷久久一区二区三区麻豆| 色窝窝无码一区二区三区成人网站| 另类视频在线观看| 91精品国产一区二区在线观看| 婷婷久久伊人| 久久精品麻豆| 少妇大叫太粗太大爽一区二区| 午夜精品久久久久久不卡8050| 精品人妻一区二区三区浪潮在线 | 国产在线播放一区| 99久久99久久精品免费看小说.| 色8久久人人97超碰香蕉987| 四虎影院在线播放| 午夜精品视频网站| baoyu135国产精品免费| 久久艹国产精品| 波多野结衣亚洲一区| 日韩毛片在线播放| 亚洲国产高潮在线观看| 98色花堂精品视频在线观看| 国产三区二区一区久久| 亚洲国产日本| 97人妻天天摸天天爽天天| 精品久久久香蕉免费精品视频| 亚洲人在线观看视频| 欧美专区在线播放| 国产欧美日韩免费观看| 亚洲一级免费在线观看| 一色桃子久久精品亚洲| jizz中国女人| 97在线视频免费播放| 免费看日本一区二区| 亚洲色图久久久| 国产精品久久久久久久久搜平片| 国产精品久久久久久久久毛片| 久青草国产97香蕉在线视频| 亚洲一区二区电影| 美女日批免费视频| 久久精品视频免费观看| 亚洲资源在线播放| 欧美成人免费小视频| 国产精品视频3p| 黑人糟蹋人妻hd中文字幕| 国产精品天美传媒| 精品久久国产视频| 91国产精品电影| 久久精品国产68国产精品亚洲| 特种兵之深入敌后| 亚洲成av人片观看| 福利视频在线导航| 亚洲一区二区三区香蕉| 亚洲精品影院在线观看| 色欲狠狠躁天天躁无码中文字幕| 欧美顶级少妇做爰| av人人综合网| 一区二区精品视频| av午夜精品一区二区三区| 在线观看你懂的网站| 色综合久久悠悠| 综合综合综合综合综合网| 蜜臀一区二区三区精品免费视频| 亚洲一区二区视频在线观看| 国产www.大片在线| 超碰在线97av| 免费一区二区视频| 国产午夜视频在线播放| 在线观看欧美日韩| 欧美激情极品| 三级黄色片免费看| 一本色道久久综合狠狠躁的推荐| 麻豆视频在线观看免费网站| 久久www免费人成精品| 国产在线不卡一卡二卡三卡四卡| 综合网在线观看| 欧美寡妇偷汉性猛交| av资源久久|