深入淺出Linux 關於mmap的解析

2021-09-21 06:04:05 字數 3688 閱讀 5567

看這篇文章之前需要知道乙個概念

虛擬記憶體系統通過將虛擬記憶體分割為稱作虛擬頁(virtual page,vp)大小固定的塊,一般情況下,每個虛擬頁的大小預設是4096位元組。同樣的,物理記憶體也被分割為物理頁(physical page,pp),也為4096位元組。

在linux中我們可以使用mmap用來在程序虛擬記憶體位址空間中分配位址空間,建立和物理記憶體的對映關係。

對映關係

對映關係可以分為兩種

1、檔案對映

磁碟檔案對映程序的虛擬位址空間,使用檔案內容初始化物理記憶體。

2、匿名對映

初始化全為0的記憶體空間。

而對於對映關係是否共享又分為

1、私有對映(map_private)

多程序間資料共享,修改不反應到磁碟實際檔案,是乙個copy-on-write(寫時複製)的對映方式。

2、共享對映(map_shared)

多程序間資料共享,修改反應到磁碟實際檔案中。

因此總結起來有4種組合

1、私有檔案對映

多個程序使用同樣的物理記憶體頁進行初始化,但是各個程序對記憶體檔案的修改不會共享,也不會反應到物理檔案中

2、私有匿名對映

mmap會建立乙個新的對映,各個程序不共享,這種使用主要用於分配記憶體(malloc分配大記憶體會呼叫mmap)。

例如開闢新程序時,會為每個程序分配虛擬的位址空間,這些虛擬位址對映的物理記憶體空間各個程序間讀的時候共享,寫的時候會copy-on-write。

3、共享檔案對映

多個程序通過虛擬記憶體技術共享同樣的物理記憶體空間,對記憶體檔案 的修改會反應到實際物理檔案中,他也是程序間通訊(ipc)的一種機制。

4、共享匿名對映

這種機制在進行fork的時候不會採用寫時複製,父子程序完全共享同樣的物理記憶體頁,這也就實現了父子程序通訊(ipc).

這裡值得注意的是,mmap只是在虛擬記憶體分配了位址空間,只有在第一次訪問虛擬記憶體的時候才分配物理記憶體。

在mmap之後,並沒有在將檔案內容載入到物理頁上,只上在虛擬記憶體中分配了位址空間。當程序在訪問這段位址時,通過查詢頁表,發現虛擬記憶體對應的頁沒有在物理記憶體中快取,則產生"缺頁",由核心的缺頁異常處理程式處理,將檔案對應內容,以頁為單位(4096)載入到物理記憶體,注意是只載入缺頁,但也會受作業系統一些排程策略影響,載入的比所需的多。

1.write

因為物理記憶體是有限的,mmap在寫入資料超過物理記憶體時,作業系統會進行頁置換,根據淘汰演算法,將需要淘汰的頁置換成所需的新頁,所以mmap對應的記憶體是可以被淘汰的(若記憶體頁是"髒"的,則作業系統會先將資料回寫磁碟再淘汰)。這樣,就算mmap的資料遠大於物理記憶體,作業系統也能很好地處理,不會產生功能上的問題。

讀的過程對比

從圖中可以看出,mmap要比普通的read系統呼叫少了一次copy的過程。因為read呼叫,程序是無法直接訪問kernel space的,所以在read系統呼叫返回前,核心需要將資料從核心複製到程序指定的buffer。但mmap之後,程序可以直接訪問mmap的資料(page cache)。

1.讀效能分析

場景:對2g的檔案進行順序寫入

每次寫入大小

mmap 耗時

write 耗時

100 bytes

2.84s

22.86s

512 bytes

2.51s

5.43s

1024 bytes

2.48s

3.48s

2048 bytes

2.47s

2.34s

4096 bytes

2.48s

1.74s

8192 bytes

2.45s

1.67s

10240 bytes

2.49s

1.65s

可以看到mmap在100byte寫入時已經基本達到最大寫入效能,而write呼叫需要在4096(也就是乙個page size)時,才能達到最大寫入效能。

從測試結果可以看出,在寫小資料時,mmap會比write呼叫快,但在寫大資料時,反而沒那麼快。

2.寫效能分析

場景:對2g的檔案進行順序讀取(為了避免磁碟對測試的影響,2g檔案都快取在pagecache中)

每次讀取大小

mmap 耗時

read 耗時

100 bytes

86.4ms

8100.9ms

512 bytes

16.14ms

1851.45ms

1024 bytes

8.11ms

992.71ms

2048 bytes

4.09ms

636.85ms

4096 bytes

2.07ms

558.10ms

8192 bytes

1.06ms

444.83ms

10240 bytes

867.88µs

475.28ms

由上可以看出,在read上面,mmap的效能還是非常好的。

優點如下:

1、對檔案的讀取操作跨過了頁快取,減少了資料的拷貝次數,用記憶體讀寫取代i/o讀寫,提高了檔案讀取效率。

2、實現了使用者空間和核心空間的高效互動方式。兩空間的各自修改操作可以直接反映在對映的區域內,從而被對方空間及時捕捉。

3、提供程序間共享記憶體及相互通訊的方式。不管是父子程序還是無親緣關係的程序,都可以將自身使用者空間對映到同乙個檔案或匿名對映到同一片區域。從而通過各自對對映區域的改動,達到程序間通訊和程序間共享的目的。同時,如果程序a和程序b都映**區域c,當a第一次讀取c時通過缺頁從磁碟複製檔案頁到記憶體中;但當b再讀c的相同頁面時,雖然也會產生缺頁異常,但是不再需要從磁碟中複製檔案過來,而可直接使用已經儲存在記憶體中的檔案資料。

4、可用於實現高效的大規模資料傳輸。記憶體空間不足,是制約大資料操作的乙個方面,解決方案往往是借助硬碟空間協助操作,補充記憶體的不足。但是進一步會造成大量的檔案i/o操作,極大影響效率。這個問題可以通過mmap對映很好的解決。換句話說,但凡是需要用磁碟空間代替記憶體的時候,mmap都可以發揮其功效。

缺點如下:

1.檔案如果很小,是小於4096位元組的,比如10位元組,由於記憶體的最小粒度是頁,而程序虛擬位址空間和記憶體的對映也是以頁為單位。雖然被對映的檔案只有10位元組,但是對應到程序虛擬位址區域的大小需要滿足整頁大小,因此mmap函式執行後,實際對映到虛擬記憶體區域的是4096個位元組,11~4096的位元組部分用零填充。因此如果連續mmap小檔案,會浪費記憶體空間。

對變長檔案不適合,檔案無法完成拓展,因為mmap到記憶體的時候,你所能夠操作的範圍就確定了。

3.如果更新檔案的操作很多,會觸發大量的髒頁回寫及由此引發的隨機io上。所以在隨機寫很多的情況下,mmap方式在效率上不一定會比帶緩衝區的一般寫快。

深入淺出sizeof

int佔 位元組,short佔 位元組 1.0 回答下列問題 答案在文章末尾 1.sizeof char 2.sizeof a 3.sizeof a 4.strlen a 如果你答對了全部四道題,那麼你可以不用細看下面關於sizeof的論述。如果你答錯了部分題目,那麼就跟著我來一起 關於sizeof...

深入淺出ShellExecute

ipconfig c log.txt應如何處理?二樓的朋友,開啟拔號網路這樣 shellexecute null,open c windows rundll32.exe shell32.dll,control rundll c windows system telephon.cpl null,sw ...

深入淺出ShellExecute

深入淺出shellexecute譯者 徐景周 原作 nishant s q 如何開啟乙個應用程式?shellexecute this m hwnd,open calc.exe sw show 或shellexecute this m hwnd,open notepad.exe c mylog.log...