精品欧美一区二区三区在线观看 _久久久久国色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技術棧公眾號

国产视频网址在线| 91美女在线观看| 国产午夜性春猛交ⅹxxx| 日本精品一二区| 最新国产拍偷乱拍精品 | 综合视频免费看| 国产精品欧美亚洲| 韩日成人av| 亚洲视频免费一区| 亚洲性图一区二区| 免费电影网站在线视频观看福利| av亚洲精华国产精华精华| 国产脚交av在线一区二区| 91成人在线免费视频| 国产日韩在线观看视频| av资源新版天堂在线| 久久99精品国产麻豆婷婷洗澡| 九九久久精品一区| 国产熟妇搡bbbb搡bbbb| 色综合久久久| 欧美日韩美女视频| 宅男一区二区三区| 天天干在线观看| 国产一区二区中文字幕| 秋霞午夜一区二区| 亚洲国产成人精品综合99| 免费视频一区三区| 日韩欧美不卡在线观看视频| 欧美私人情侣网站| 天天干在线视频论坛| 国产日韩精品一区| 91亚洲国产成人久久精品网站| 日韩精品久久久久久久酒店| 欧美裸体在线版观看完整版| 亚洲成人黄色在线观看| 亚洲 国产 图片| 中文字幕色婷婷在线视频| 国产精品国产三级国产普通话三级| 国产精品久久久久久久久久久久冷| 中文字幕免费高清在线观看| 午夜亚洲性色福利视频| 久久久久久亚洲| 99热99这里只有精品| 亚洲第一论坛sis| 精品国产sm最大网站| av网站在线不卡| 国内老司机av在线| 亚洲欧美另类图片小说| 欧美精品尤物在线| 亚洲欧美另类视频| 国产成人精品aa毛片| 成人激情免费在线| 911美女片黄在线观看游戏| 久久性天堂网| 国产91在线播放精品91| 久久久久久久久影院| 亚洲视频观看| 欧美韩日一区二区| 校园春色 亚洲| 在线中文字幕第一区| 久久视频国产精品免费视频在线 | 国产视频第一页| 奇米亚洲午夜久久精品| 国产精品国产福利国产秒拍| 波多野结衣一区二区三区在线| 久久大逼视频| 国产精品69精品一区二区三区| 国产www在线| 日韩综合一区二区| 国产精品第2页| 在线播放成人av| 久久99国产精品免费| 91亚洲精品视频| 午夜免费福利视频| 成人免费电影视频| 精品日本一区二区| 国产一二三区在线| 国产精品嫩草影院av蜜臀| 亚洲视频sss| 91网址在线观看| 亚洲成av人影院在线观看网| 青青草视频在线免费播放| 偷拍自拍在线看| 欧美日韩免费高清一区色橹橹| www.污污视频| 99久热这里只有精品视频免费观看| 精品99一区二区| 久久国产精品影院| 欧美oldwomenvideos| 欧美成人精品在线播放| 国产精选第一页| 夜久久久久久| 国产精品亚洲网站| 亚洲AV无码国产精品午夜字幕 | 国产精品一级久久久| 婷婷色在线视频| 国产精品污www在线观看| 欧美少妇一级片| 91禁在线看| 欧美艳星brazzers| youjizz.com日本| 成人av二区| 欧美激情欧美激情在线五月| 日本高清不卡码| 国产乱一区二区| 欧美日韩在线一二三| 尤物视频在线看| 91国产免费看| 超碰caoprom| 欧美mv日韩| 欧洲日本亚洲国产区| 国产乱码精品一区二区| 91丨porny丨户外露出| 中文字幕精品一区日韩| 狠狠操一区二区三区| 欧美酷刑日本凌虐凌虐| 美国黄色一级毛片| 婷婷综合五月| 日本精品视频在线观看| 精品区在线观看| 国产精品入口麻豆九色| 亚洲美免无码中文字幕在线| av一级久久| 一区二区三区视频观看| 日韩精品无码一区二区| 精品一区二区三区蜜桃| 欧美日韩国产综合在线| 爱情岛论坛亚洲品质自拍视频网站| 欧美人xxxx| 超碰97人人干| 亚洲天堂激情| 亚洲一区二区久久久久久| 美州a亚洲一视本频v色道| 亚洲综合在线免费观看| 欧美一级xxxx| 日本一区二区三区视频| 日本久久久久久久久久久| 污视频网站免费观看| 一区二区高清免费观看影视大全| 中文字幕 日韩 欧美| 欧美伦理影院| 国产精品av在线播放| 免费在线超碰| 色久综合一二码| 免费黄色在线视频| 亚洲一区图片| 久久婷婷开心| 麻豆免费版在线观看| 亚洲国产精品小视频| 1024手机在线视频| 国产一区在线看| 国产成人三级视频| 国产精品99久久免费| 久久精品色欧美aⅴ一区二区| 中文天堂在线资源| 国产精品色在线观看| 污污网站免费看| 久久裸体网站| 91九色视频在线| 精精国产xxxx视频在线| 欧美一区二区三区日韩| 国产精品老熟女一区二区| 国产成人一级电影| 国产免费一区二区视频| 美女午夜精品| 国产不卡视频在线| 香港伦理在线| 日韩欧美你懂的| 久久亚洲精品大全| 91在线一区二区| 88av.com| 午夜精品视频一区二区三区在线看| 91沈先生作品| 久草在线资源站资源站| 精品国产麻豆免费人成网站| 国产奶水涨喷在线播放| 2021久久国产精品不只是精品| 国产第一页视频| 99久久综合狠狠综合久久aⅴ| 亚洲999一在线观看www| 乱插在线www| 亚洲美女中文字幕| 亚洲天堂网在线视频| 亚洲另类色综合网站| 中国极品少妇xxxx| 日日嗨av一区二区三区四区| 99热都是精品| 免费看日本一区二区| 国产伊人精品在线| 大香伊人久久| 国产亚洲人成a一在线v站| 国产女18毛片多18精品| 午夜精品福利一区二区蜜股av| 粉嫩av蜜桃av蜜臀av| 久久www免费人成看片高清| 99热久久这里只有精品| 欧美午夜精品一区二区三区电影| 91亚洲一区精品| 亚洲精品mv| 久久99久国产精品黄毛片入口| 色网站免费观看| 欧美日韩亚洲综合| 日本一区二区网站| 亚洲欧洲三级电影| 黄色正能量网站| 麻豆精品一区二区综合av| r级无码视频在线观看| 欧美色女视频| 好吊色欧美一区二区三区| 亚洲日日夜夜| 日本一区二区在线免费播放| 伊人电影在线观看| 综合国产在线视频| 亚洲色大成网站www| 欧美一区二区视频在线观看2022 | 午夜亚洲性色福利视频| 国产精品波多野结衣| 免费看日本一区二区| 国产精品日韩二区| 国产日韩在线观看视频| 国产精品视频久久| 日韩福利一区| 91精品国产乱码久久久久久蜜臀| 成人免费观看视频大全| 中文字幕av一区| 亚洲av片一区二区三区| 欧美sm美女调教| 国产精品热久久| 欧美日韩精品高清| 一二三区免费视频| 欧美视频不卡中文| 日本三级视频在线| 一区二区三区欧美在线观看| 国产免费一区二区三区四区| 亚洲国产精品二十页| 国产真实乱人偷精品人妻| 99re成人在线| 亚洲国产果冻传媒av在线观看| 国产98色在线|日韩| 少妇丰满尤物大尺度写真| 麻豆成人av在线| 日本久久久久久久久久久久| 日韩在线观看一区二区| 久久精品网站视频| 久久婷婷影院| 牛夜精品久久久久久久| 久久国产麻豆精品| 亚洲一级免费在线观看| 久久精品国产精品亚洲红杏| 久久99999| 奇米影视在线99精品| 一级片视频免费观看| 加勒比av一区二区| 日本中文字幕在线不卡| 国产成人a级片| 久久久无码人妻精品无码| 国产成人在线影院| 在线xxxxx| 99久久精品国产毛片| 亚洲一区二区观看| 国产欧美日韩一区二区三区在线观看| www.狠狠爱| 中文字幕一区二区三区色视频| 久久精品一区二区三区四区五区| 亚洲毛片av在线| 国产精品日日夜夜| 欧美日韩免费在线| 国产99久久久久久免费看| 欧美日韩一级黄| 精品国自产在线观看| 精品av久久707| 国产系列在线观看| 久久色精品视频| 91探花在线观看| 国产精品成av人在线视午夜片| 欧美国产视频| 成人免费在线一区二区三区| 欧美精品中文| 亚洲高清视频在线观看| 欧美福利影院| 久草资源站在线观看| 另类调教123区| 中文字幕第九页| 久久久久国色av免费看影院| 91香蕉视频污在线观看| 亚洲成av人片| 中文字幕av无码一区二区三区| 91精品国产一区二区三区香蕉| 熟妇人妻av无码一区二区三区| 亚洲毛片在线观看.| 快射视频在线观看| 8x拔播拔播x8国产精品| 免费视频观看成人| 国产一区二区中文字幕免费看| 欧美美乳视频| 妞干网在线播放| 视频一区国产视频| 丰满饥渴老女人hd| 亚洲国产经典视频| 在线免费观看毛片| 欧美丰满一区二区免费视频| 天天摸天天干天天操| 久久久精品日本| 秋霞国产精品| 国产无套精品一区二区| 亚洲精品电影| 激情五月亚洲色图| 成人精品鲁一区一区二区| 欧美福利在线视频| 色综合咪咪久久| 亚洲精品18p| 久久久成人av| 一二区成人影院电影网| 国产偷国产偷亚洲高清97cao| 国产精品7m凸凹视频分类| 成人久久久久久久久| 福利电影一区二区三区| jizzjizz日本少妇| 91成人网在线| 日漫免费在线观看网站| 欧美精品精品精品精品免费| 自拍偷拍亚洲图片| 日韩亚洲视频在线| 免费看黄裸体一级大秀欧美| 午夜影院福利社| 亚洲丝袜美腿综合| 亚洲天堂视频在线| 在线观看国产成人av片| 综合久久2023| 久久99精品国产一区二区三区| 欧美精品aa| 欧美熟妇另类久久久久久多毛| 国产精品国产三级国产普通话蜜臀 | 日韩欧美在线字幕| 欧美一级淫片免费视频魅影视频| 精品国产依人香蕉在线精品| av在线一区不卡| 日韩成人在线资源| 久久综合网络一区二区| 97伦伦午夜电影理伦片| 舔着乳尖日韩一区| 亚洲欧洲国产综合| 17婷婷久久www| 日韩av影院| 男人揉女人奶房视频60分| av成人老司机| 久久久免费高清视频| 亚洲精品影视在线观看| 高清不卡av| 日韩免费中文专区| 欧美aⅴ一区二区三区视频| 麻豆视频免费在线播放| 欧美色图在线观看| 欧美精品日韩少妇| 91美女片黄在线观看游戏| 永久亚洲成a人片777777| 韩国三级hd中文字幕有哪些| 亚洲狠狠丁香婷婷综合久久久| 国产三级第一页| 欧美激情一区二区久久久| 美女av一区| 久久久久久久少妇| 国产精品入口麻豆九色| 国产精品嫩草影院精东| 欧美激情第一页xxx| 果冻天美麻豆一区二区国产| 91精品91久久久中77777老牛| 国产夜色精品一区二区av| 亚洲在线免费观看视频| 欧美成人精品在线播放| 日韩电影不卡一区| 亚洲天堂av线| 亚洲女人的天堂| 手机看片一区二区| 国产精品专区一| 欧美国产激情| 性欧美成人播放77777| 欧美性大战久久久久久久蜜臀| 免费黄网在线观看| 国产精品国色综合久久| 日韩av中文字幕一区二区三区| 亚洲av无一区二区三区| 欧美大片拔萝卜| 亚洲黄色免费看| 懂色av一区二区三区四区五区| 国产成a人亚洲| 久久久精品毛片| 欧美剧在线观看| 久久91麻豆精品一区| 欧美体内she精高潮| 狠狠爱在线视频一区| 久久久久久国产精品免费无遮挡 | 欧美亚洲在线日韩| 亚洲AV成人精品| 欧美视频你懂的| segui88久久综合| 伊人精品久久久久7777| 99久久国产综合精品色伊| 亚洲在线视频播放| 秋霞午夜一区二区|