在C/C++ 中常用的內(nèi)存分配和管理的方式有很多,如智能指針, STL容器, new/delete, malloc/free, brk, sbrk等等,最近研究了一下Unix比較底層的一種內(nèi)存管理方式mmap/munmap,需要完全自己來(lái)維護(hù)分配的虛擬內(nèi)存,沒有任何其他輔助的數(shù)據(jù)結(jié)構(gòu)來(lái)幫助維護(hù)內(nèi)存空間,但其優(yōu)點(diǎn)就是效率比其他的內(nèi)存分配方式要高。
一、在終端里輸入 man mmap 可以查看此函數(shù)的API文檔,此函數(shù)的具體描述如下:
void *mmap(void *start,size_t length,int prot,int flags,int fd,off_t offsize);
具體參數(shù)含義
start : 指向欲映射的內(nèi)存起始地址,通常設(shè)為 NULL,代表讓系統(tǒng)自動(dòng)選定地址,映射成功后返回該地址。
length: 代表將文件中多大的部分映射到內(nèi)存。
prot : 映射區(qū)域的保護(hù)方式。可以為以下幾種方式的組合:
PROT_EXEC 映射區(qū)域可被執(zhí)行
PROT_READ 映射區(qū)域可被讀取
PROT_WRITE 映射區(qū)域可被寫入
PROT_NONE 映射區(qū)域不能存取
flags : 影響映射區(qū)域的各種特性。在調(diào)用mmap()時(shí)必須要指定MAP_SHARED 或MAP_PRIVATE。
MAP_FIXED 如果參數(shù)start所指的地址無(wú)法成功建立映射時(shí),則放棄映射,不對(duì)地址做修正。通常不鼓勵(lì)用此旗標(biāo)。
MAP_SHARED 對(duì)映射區(qū)域的寫入數(shù)據(jù)會(huì)復(fù)制回文件內(nèi),而且允許其他映射該文件的進(jìn)程共享。
MAP_PRIVATE 對(duì)映射區(qū)域的寫入操作會(huì)產(chǎn)生一個(gè)映射文件的復(fù)制,即私人的“寫入時(shí)復(fù)制”(copy on write)對(duì)此區(qū)域作的任何修改都不會(huì)寫回原來(lái)的文件內(nèi)容。
MAP_ANONYMOUS建立匿名映射。此時(shí)會(huì)忽略參數(shù)fd,不涉及文件,而且映射區(qū)域無(wú)法和其他進(jìn)程共享。
MAP_DENYWRITE只允許對(duì)映射區(qū)域的寫入操作,其他對(duì)文件直接寫入的操作將會(huì)被拒絕。
MAP_LOCKED 將映射區(qū)域鎖定住,這表示該區(qū)域不會(huì)被置換(swap)。
fd : 要映射到內(nèi)存中的文件描述符。如果使用匿名內(nèi)存映射時(shí),即flags中設(shè)置了MAP_ANONYMOUS,fd設(shè)為-1。有些系統(tǒng)不支持匿名內(nèi)存映射,則可以使用fopen打開/dev/zero文件,
然后對(duì)該文件進(jìn)行映射,可以同樣達(dá)到匿名內(nèi)存映射的效果。
offset:文件映射的偏移量,通常設(shè)置為0,代表從文件最前方開始對(duì)應(yīng),offset必須是PAGE_SIZE的整數(shù)倍。
返回值:
若映射成功則返回映射區(qū)的內(nèi)存起始地址,否則返回MAP_FAILED(-1),錯(cuò)誤原因存于errno 中。
錯(cuò)誤代碼:
EBADF 參數(shù)fd 不是有效的文件描述詞
EACCES 存取權(quán)限有誤。如果是MAP_PRIVATE 情況下文件必須可讀,使用MAP_SHARED則要有PROT_WRITE以及該文件要能寫入。
EINVAL 參數(shù)start、length 或offset有一個(gè)不合法。
EAGAIN 文件被鎖住,或是有太多內(nèi)存被鎖住。
ENOMEM 內(nèi)存不足。
用戶層的調(diào)用很簡(jiǎn)單,其具體功能就是直接將物理內(nèi)存直接映射到用戶虛擬內(nèi)存,使用戶空間可以直接對(duì)物理空間操作。但是對(duì)于內(nèi)核層而言,其具體實(shí)現(xiàn)比較復(fù)雜。
二、例子程序如下
我是在64位的Mac OS X系統(tǒng)下編譯運(yùn)行的,64位系統(tǒng)內(nèi)存頁(yè)的大小為8k, 32位為4k
上一篇 C++ Singleton
下一篇 二進(jìn)制加法