前言
看這篇文章之前需要知道一個(gè)概念
虛擬內(nèi)存系統(tǒng)通過(guò)將虛擬內(nèi)存分割為稱作虛擬頁(yè)(Virtual Page荸频,VP)大小固定的塊选泻,一般情況下窝稿,每個(gè)虛擬頁(yè)的大小默認(rèn)是4096字節(jié)祝闻。同樣的奕谭,物理內(nèi)存也被分割為物理頁(yè)(Physical Page,PP)贵涵,也為4096字節(jié)列肢。
一、mmap基本原理和分類
在LINUX中我們可以使用mmap用來(lái)在進(jìn)程虛擬內(nèi)存地址空間中分配地址空間独悴,創(chuàng)建和物理內(nèi)存的映射關(guān)系例书。
映射關(guān)系可以分為兩種
1、文件映射
磁盤(pán)文件映射進(jìn)程的虛擬地址空間刻炒,使用文件內(nèi)容初始化物理內(nèi)存决采。
2、匿名映射
初始化全為0的內(nèi)存空間坟奥。
而對(duì)于映射關(guān)系是否共享又分為
1树瞭、私有映射(MAP_PRIVATE)
多進(jìn)程間數(shù)據(jù)共享,修改不反應(yīng)到磁盤(pán)實(shí)際文件爱谁,是一個(gè)copy-on-write(寫(xiě)時(shí)復(fù)制)的映射方式晒喷。
2、共享映射(MAP_SHARED)
多進(jìn)程間數(shù)據(jù)共享访敌,修改反應(yīng)到磁盤(pán)實(shí)際文件中凉敲。
因此總結(jié)起來(lái)有4種組合
1、私有文件映射
多個(gè)進(jìn)程使用同樣的物理內(nèi)存頁(yè)進(jìn)行初始化寺旺,但是各個(gè)進(jìn)程對(duì)內(nèi)存文件的修改不會(huì)共享爷抓,也不會(huì)反應(yīng)到物理文件中
2、私有匿名映射
mmap會(huì)創(chuàng)建一個(gè)新的映射阻塑,各個(gè)進(jìn)程不共享蓝撇,這種使用主要用于分配內(nèi)存(malloc分配大內(nèi)存會(huì)調(diào)用mmap)。
例如開(kāi)辟新進(jìn)程時(shí)陈莽,會(huì)為每個(gè)進(jìn)程分配虛擬的地址空間渤昌,這些虛擬地址映射的物理內(nèi)存空間各個(gè)進(jìn)程間讀的時(shí)候共享,寫(xiě)的時(shí)候會(huì)copy-on-write走搁。
3独柑、共享文件映射
多個(gè)進(jìn)程通過(guò)虛擬內(nèi)存技術(shù)共享同樣的物理內(nèi)存空間,對(duì)內(nèi)存文件 的修改會(huì)反應(yīng)到實(shí)際物理文件中私植,他也是進(jìn)程間通信(IPC)的一種機(jī)制忌栅。
4、共享匿名映射
這種機(jī)制在進(jìn)行fork的時(shí)候不會(huì)采用寫(xiě)時(shí)復(fù)制兵琳,父子進(jìn)程完全共享同樣的物理內(nèi)存頁(yè)狂秘,這也就實(shí)現(xiàn)了父子進(jìn)程通信(IPC).
這里值得注意的是,mmap只是在虛擬內(nèi)存分配了地址空間躯肌,只有在第一次訪問(wèn)虛擬內(nèi)存的時(shí)候才分配物理內(nèi)存者春。
在mmap之后,并沒(méi)有在將文件內(nèi)容加載到物理頁(yè)上清女,只上在虛擬內(nèi)存中分配了地址空間钱烟。當(dāng)進(jìn)程在訪問(wèn)這段地址時(shí),通過(guò)查找頁(yè)表嫡丙,發(fā)現(xiàn)虛擬內(nèi)存對(duì)應(yīng)的頁(yè)沒(méi)有在物理內(nèi)存中緩存拴袭,則產(chǎn)生"缺頁(yè)",由內(nèi)核的缺頁(yè)異常處理程序處理曙博,將文件對(duì)應(yīng)內(nèi)容拥刻,以頁(yè)為單位(4096)加載到物理內(nèi)存,注意是只加載缺頁(yè)父泳,但也會(huì)受操作系統(tǒng)一些調(diào)度策略影響般哼,加載的比所需的多。
二.mmap在write和read時(shí)會(huì)發(fā)生什么
1.write
- 1.進(jìn)程(用戶態(tài))將需要寫(xiě)入的數(shù)據(jù)直接copy到對(duì)應(yīng)的mmap地址(內(nèi)存copy)
- 2.若mmap地址未對(duì)應(yīng)物理內(nèi)存惠窄,則產(chǎn)生缺頁(yè)異常蒸眠,由內(nèi)核處理
- 3.若已對(duì)應(yīng),則直接copy到對(duì)應(yīng)的物理內(nèi)存
- 4.由操作系統(tǒng)調(diào)用杆融,將臟頁(yè)回寫(xiě)到磁盤(pán)(通常是異步的)
因?yàn)槲锢韮?nèi)存是有限的楞卡,mmap在寫(xiě)入數(shù)據(jù)超過(guò)物理內(nèi)存時(shí),操作系統(tǒng)會(huì)進(jìn)行頁(yè)置換脾歇,根據(jù)淘汰算法蒋腮,將需要淘汰的頁(yè)置換成所需的新頁(yè),所以mmap對(duì)應(yīng)的內(nèi)存是可以被淘汰的(若內(nèi)存頁(yè)是"臟"的介劫,則操作系統(tǒng)會(huì)先將數(shù)據(jù)回寫(xiě)磁盤(pán)再淘汰)徽惋。這樣,就算mmap的數(shù)據(jù)遠(yuǎn)大于物理內(nèi)存座韵,操作系統(tǒng)也能很好地處理险绘,不會(huì)產(chǎn)生功能上的問(wèn)題。
2.read
從圖中可以看出誉碴,mmap要比普通的read系統(tǒng)調(diào)用少了一次copy的過(guò)程宦棺。因?yàn)閞ead調(diào)用,進(jìn)程是無(wú)法直接訪問(wèn)kernel space的黔帕,所以在read系統(tǒng)調(diào)用返回前代咸,內(nèi)核需要將數(shù)據(jù)從內(nèi)核復(fù)制到進(jìn)程指定的buffer。但mmap之后成黄,進(jìn)程可以直接訪問(wèn)mmap的數(shù)據(jù)(page cache)呐芥。
三.性能分析
測(cè)試結(jié)果來(lái)源于:深入剖析mmap-從三個(gè)關(guān)鍵問(wèn)題說(shuō)起
1.讀性能分析
場(chǎng)景:對(duì)2G的文件進(jìn)行順序?qū)懭?/p>
每次寫(xiě)入大小 | mmap 耗時(shí) | write 耗時(shí) |
---|---|---|
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寫(xiě)入時(shí)已經(jīng)基本達(dá)到最大寫(xiě)入性能逻杖,而write調(diào)用需要在4096(也就是一個(gè)page size)時(shí),才能達(dá)到最大寫(xiě)入性能思瘟。
從測(cè)試結(jié)果可以看出荸百,在寫(xiě)小數(shù)據(jù)時(shí),mmap會(huì)比write調(diào)用快滨攻,但在寫(xiě)大數(shù)據(jù)時(shí)够话,反而沒(méi)那么快。
2.寫(xiě)性能分析
場(chǎng)景:對(duì)2G的文件進(jìn)行順序讀裙馊啤(為了避免磁盤(pán)對(duì)測(cè)試的影響女嘲,2G文件都緩存在pagecache中)
每次讀取大小 | mmap 耗時(shí) | read 耗時(shí) |
---|---|---|
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的性能還是非常好的欣尼。
四.總結(jié)
優(yōu)點(diǎn)如下:
1、對(duì)文件的讀取操作跨過(guò)了頁(yè)緩存景埃,減少了數(shù)據(jù)的拷貝次數(shù)媒至,用內(nèi)存讀寫(xiě)取代I/O讀寫(xiě),提高了文件讀取效率谷徙。
2拒啰、實(shí)現(xiàn)了用戶空間和內(nèi)核空間的高效交互方式。兩空間的各自修改操作可以直接反映在映射的區(qū)域內(nèi)完慧,從而被對(duì)方空間及時(shí)捕捉谋旦。
3、提供進(jìn)程間共享內(nèi)存及相互通信的方式屈尼。不管是父子進(jìn)程還是無(wú)親緣關(guān)系的進(jìn)程册着,都可以將自身用戶空間映射到同一個(gè)文件或匿名映射到同一片區(qū)域。從而通過(guò)各自對(duì)映射區(qū)域的改動(dòng)脾歧,達(dá)到進(jìn)程間通信和進(jìn)程間共享的目的甲捏。同時(shí),如果進(jìn)程A和進(jìn)程B都映射了區(qū)域C鞭执,當(dāng)A第一次讀取C時(shí)通過(guò)缺頁(yè)從磁盤(pán)復(fù)制文件頁(yè)到內(nèi)存中司顿;但當(dāng)B再讀C的相同頁(yè)面時(shí),雖然也會(huì)產(chǎn)生缺頁(yè)異常兄纺,但是不再需要從磁盤(pán)中復(fù)制文件過(guò)來(lái)大溜,而可直接使用已經(jīng)保存在內(nèi)存中的文件數(shù)據(jù)。
4估脆、可用于實(shí)現(xiàn)高效的大規(guī)模數(shù)據(jù)傳輸钦奋。內(nèi)存空間不足,是制約大數(shù)據(jù)操作的一個(gè)方面,解決方案往往是借助硬盤(pán)空間協(xié)助操作付材,補(bǔ)充內(nèi)存的不足朦拖。但是進(jìn)一步會(huì)造成大量的文件I/O操作,極大影響效率厌衔。這個(gè)問(wèn)題可以通過(guò)mmap映射很好的解決贞谓。換句話說(shuō),但凡是需要用磁盤(pán)空間代替內(nèi)存的時(shí)候葵诈,mmap都可以發(fā)揮其功效。
缺點(diǎn)如下:
1.文件如果很小祟同,是小于4096字節(jié)的作喘,比如10字節(jié),由于內(nèi)存的最小粒度是頁(yè)晕城,而進(jìn)程虛擬地址空間和內(nèi)存的映射也是以頁(yè)為單位泞坦。雖然被映射的文件只有10字節(jié),但是對(duì)應(yīng)到進(jìn)程虛擬地址區(qū)域的大小需要滿足整頁(yè)大小砖顷,因此mmap函數(shù)執(zhí)行后贰锁,實(shí)際映射到虛擬內(nèi)存區(qū)域的是4096個(gè)字節(jié),11~4096的字節(jié)部分用零填充滤蝠。因此如果連續(xù)mmap小文件豌熄,會(huì)浪費(fèi)內(nèi)存空間。
- 對(duì)變長(zhǎng)文件不適合物咳,文件無(wú)法完成拓展锣险,因?yàn)閙map到內(nèi)存的時(shí)候,你所能夠操作的范圍就確定了览闰。
3.如果更新文件的操作很多芯肤,會(huì)觸發(fā)大量的臟頁(yè)回寫(xiě)及由此引發(fā)的隨機(jī)IO上。所以在隨機(jī)寫(xiě)很多的情況下压鉴,mmap方式在效率上不一定會(huì)比帶緩沖區(qū)的一般寫(xiě)快崖咨。