自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Mmap內(nèi)存映射的原理以及實(shí)現(xiàn)

開發(fā) 前端
這段代碼實(shí)現(xiàn)了將測(cè)試文件testdata打開,并用mmap函數(shù)將文件映射到虛擬內(nèi)存中,通過指針start對(duì)文件進(jìn)行讀寫。在終端中可看到由文件讀取的數(shù)據(jù)。程序結(jié)束后,可以查看testdata文件,來查看寫入的數(shù)據(jù)

面試和工作中可能會(huì)用到mmap內(nèi)存映射,今天就來聊一聊

1、mmap基礎(chǔ)概念

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

圖片

mmap 具有如下的特點(diǎn):

  • mmap 向應(yīng)用程序提供的內(nèi)存訪問接口是內(nèi)存地址連續(xù)的,但是對(duì)應(yīng)的磁盤文件的 block 可以不是地址連續(xù)的;
  • mmap 提供的內(nèi)存空間是虛擬空間(虛擬內(nèi)存),而不是物理空間(物理內(nèi)存),因此完全可以分配遠(yuǎn)遠(yuǎn)大于物理內(nèi)存大小的虛擬空間(例如 16G 內(nèi)存主機(jī)分配 1000G 的 mmap 內(nèi)存空間);
  • mmap 負(fù)責(zé)映射文件邏輯上一段連續(xù)的數(shù)據(jù)(物理上可以不連續(xù)存儲(chǔ))映射為連續(xù)內(nèi)存,而這里的文件可以是磁盤文件、驅(qū)動(dòng)假造出的文件(例如 DMA 技術(shù))以及設(shè)備;
  • mmap 由操作系統(tǒng)負(fù)責(zé)管理,對(duì)同一個(gè)文件地址的映射將被所有線程共享,操作系統(tǒng)確保線程安全以及線程可見性;
  • mmap 的設(shè)計(jì)很有啟發(fā)性?;诖疟P的讀寫單位是 block(一般大小為 4KB),而基于內(nèi)存的讀寫單位是地址(雖然內(nèi)存的管理與分配單位是 4KB)。換言之,CPU 進(jìn)行一次磁盤讀寫操作涉及的數(shù)據(jù)量至少是 4KB,但是進(jìn)行一次內(nèi)存操作涉及的數(shù)據(jù)量是基于地址的,也就是通常的 64bit(64 位操作系統(tǒng))。mmap 下進(jìn)程可以采用指針的方式進(jìn)行讀寫操作,這是值得注意的;

2、mmap內(nèi)存映射原理

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

2.1進(jìn)程啟動(dòng)映射過程,并在虛擬地址空間中為映射創(chuàng)建虛擬映射區(qū)域;

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

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

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

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

  • 前兩個(gè)階段僅在于創(chuàng)建虛擬區(qū)間并完成地址映射,但是并沒有將任何文件數(shù)據(jù)的拷貝至主存。真正的文件讀取是當(dāng)進(jìn)程發(fā)起讀或?qū)懖僮鲿r(shí);
  •  進(jìn)程的讀或?qū)懖僮髟L問虛擬地址空間這一段映射地址,通過查詢頁表,發(fā)現(xiàn)這一段地址并不在物理頁面上。因?yàn)槟壳爸唤⒘说刂酚成?,真正的硬盤數(shù)據(jù)還沒有拷貝到內(nèi)存中,因此引發(fā)缺頁異常;
  •  缺頁異常進(jìn)行一系列判斷,確定無非法操作后,內(nèi)核發(fā)起請(qǐng)求調(diào)頁過程。
  •  調(diào)頁過程先在交換緩存空間(swap cache)中尋找需要訪問的內(nèi)存頁,如果沒有則調(diào)用nopage函數(shù)把所缺的頁從磁盤裝入到主存中;
  • 1之后進(jìn)程即可對(duì)這片主存進(jìn)行讀或者寫的操作,如果寫操作改變了其內(nèi)容,一定時(shí)間后系統(tǒng)會(huì)自動(dòng)回寫臟頁面到對(duì)應(yīng)磁盤地址,也即完成了寫入到文件的過程;
  • 修改過的臟頁面并不會(huì)立即更新回文件中,而是有一段時(shí)間的延遲,可以調(diào)用msync()來強(qiáng)制同步, 這樣所寫的內(nèi)容就能立即保存到文件里了;

3、mmap函數(shù)實(shí)例分析

3.1mmap函數(shù)的原型

void *mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset);

參數(shù)addr:指定映射的起始地址,通常設(shè)為NULL,由內(nèi)核來分配

參數(shù)length:代表將文件中映射到內(nèi)存的部分的長度。

參數(shù)prot:映射區(qū)域的保護(hù)方式??梢詾橐韵聨追N方式的組合:

  • PROT_EXEC 映射區(qū)域可被執(zhí)行
  • PROT_READ 映射區(qū)域可被讀取
  • PROT_WRITE 映射區(qū)域可被寫入
  • PROT_NONE 映射區(qū)域不能存取

參數(shù)flags:映射區(qū)的特性標(biāo)志位,常用的兩個(gè)選項(xiàng)是:

  • MAP_SHARD:寫入映射區(qū)的數(shù)據(jù)會(huì)復(fù)制回文件,且運(yùn)行其他映射文件的進(jìn)程共享
  • MAP_PRIVATE:對(duì)映射區(qū)的寫入操作會(huì)產(chǎn)生一個(gè)映射區(qū)的復(fù)制,對(duì)此區(qū)域的修改不會(huì)寫會(huì)原文件

參數(shù)fd:要映射到內(nèi)存中的文件描述符,有open函數(shù)打開文件時(shí)返回的值。

參數(shù)offset:文件映射的偏移量,通常設(shè)置為0,代表從文件最前方開始對(duì)應(yīng),offset必須是分頁大小的整數(shù)倍。

函數(shù)返回值:實(shí)際分配的內(nèi)存的起始地址

3.2munmap函數(shù)

與mmap函數(shù)成對(duì)使用的是munmap函數(shù),它是用來解除映射的函數(shù);

int munmap(void *start, size_t length)

  • 參數(shù)start:映射的起始地址
  • 參數(shù)length:文件中映射到內(nèi)存的部分的長度
  • 返回值:解除成功返回0,失敗返回-1

3.3實(shí)例

下面是一個(gè)mmap使用的實(shí)例代碼

//打開文件
fd = open("testdata",O_RDWR);
//創(chuàng)建mmap
start = (char *)mmap(NULL,128,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);
//讀取文件
strcpy(buf,start);
printf("%s\n",buf);
//寫入文件
strcpy(start,"Write to file!\n");
munmap(start,128);
close(fd);

這段代碼實(shí)現(xiàn)了將測(cè)試文件testdata打開,并用mmap函數(shù)將文件映射到虛擬內(nèi)存中,通過指針start對(duì)文件進(jìn)行讀寫。在終端中可看到由文件讀取的數(shù)據(jù)。程序結(jié)束后,可以查看testdata文件,來查看寫入的數(shù)據(jù)



責(zé)任編輯:武曉燕 來源: Android開發(fā)編程
相關(guān)推薦

2011-04-25 17:15:39

MongodbMMAP

2021-11-11 05:00:02

JavaMmap內(nèi)存

2014-07-28 11:20:20

mmap虛擬映射Linux

2024-01-05 07:55:39

Linux虛擬內(nèi)存

2023-05-11 08:28:54

Pythonmmap()函數(shù)

2009-08-13 14:21:04

.NET內(nèi)存映射文件

2021-06-30 10:32:33

反射多態(tài)Java

2020-10-09 07:13:11

Linux系統(tǒng)編程mmap

2017-10-26 21:08:15

Tomcat可插拔SCI

2021-04-27 13:56:49

內(nèi)存.映射地址

2009-09-07 05:24:22

C#窗體繼承

2019-12-09 15:20:09

JavascriptPromise前端

2022-07-11 20:46:39

AQSJava

2016-01-13 09:19:27

2019-12-04 10:23:33

HBase內(nèi)存MemStore

2021-10-20 07:18:50

開源輕量級(jí)緩存

2013-10-12 13:01:51

Linux運(yùn)維內(nèi)存管理

2009-07-24 10:00:38

.NET 4.0內(nèi)存映

2023-11-23 08:31:51

競(jìng)爭鎖共享字段

2012-06-20 14:16:36

Java內(nèi)存映射
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)