日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux mmap 内存映射【转】

發(fā)布時(shí)間:2024/4/14 linux 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux mmap 内存映射【转】 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

轉(zhuǎn)自:http://blog.csdn.net/xyyangkun/article/details/7830313

[-]

  • mmap vs readwritelseek
  • mmap vs malloc
  • mmap共享內(nèi)存進(jìn)程通信
  • 總結(jié)
  • http://www.perfgeeks.com/?p=723

    ?

    ?

    mmap() vs read()/write()/lseek()

    通過strace統(tǒng)計(jì)系統(tǒng)調(diào)用的時(shí)候,經(jīng)常可以看到mmap()與mmap2()。系統(tǒng)調(diào)用mmap()可以將某文件映射至內(nèi)存(進(jìn)程空間),如此可以把對(duì)文件的操作轉(zhuǎn)為對(duì)內(nèi)存的操作,以此避免更多的lseek()與read()、write()操作,這點(diǎn)對(duì)于大文件或者頻繁訪問的文件而言尤其受益。但有一點(diǎn)必須清楚:mmap的addr與offset必須對(duì)齊一個(gè)內(nèi)存頁面大小的邊界,即內(nèi)存映射往往是頁面大小的整數(shù)倍,否則maaped_file_size%page_size內(nèi)存空間將被閑置浪費(fèi)。

    演示一下,將文件/tmp/file_mmap中的字符轉(zhuǎn)成大寫,分別使用mmap與read/write二種方法實(shí)現(xiàn)。

    /* * @file: t_mmap.c */ #include <stdio.h> #include <ctype.h> #include <sys/mman.h> /*mmap munmap*/ #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> ? int main(int argc, char *argv[]) { int fd; char *buf; off_t len; struct stat sb; char *fname = "/tmp/file_mmap"; ? fd = open(fname, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); if (fd == -1) { perror("open"); return 1; } if (fstat(fd, &sb) == -1) { perror("fstat"); return 1; } ? buf = mmap(0, sb.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (buf == MAP_FAILED) { perror("mmap"); return 1; } ? if (close(fd) == -1) { perror("close"); return 1; } ? for (len = 0; len < sb.st_size; ++len) { buf[len] = toupper(buf[len]); /*putchar(buf[len]);*/ } ? if (munmap(buf, sb.st_size) == -1) { perror("munmap"); return 1; } return 0; } #gcc –o t_mmap t_mmap.c #strace ./t_mmap open("/tmp/file_mmap", O_RDWR|O_CREAT, 0600) = 3 //open,返回fd=3 fstat64(3, {st_mode=S_IFREG|0644, st_size=18, ...}) = 0 //fstat, 即文件大小18 mmap2(NULL, 18, PROT_READ|PROT_WRITE, MAP_SHARED, 3, 0) = 0xb7867000 //mmap文件fd=3 close(3) = 0 //close文件fd=3 munmap(0xb7867000, 18) = 0 //munmap,移除0xb7867000這里的內(nèi)存映射

    雖然沒有看到read/write寫文件操作,但此時(shí)文件/tmp/file_mmap中的內(nèi)容已由www.perfgeeks.com改變成了WWW.PERFGEEKS.COM .這里mmap的addr是0(NULL),offset是18,并不是一個(gè)內(nèi)存頁的整數(shù)倍,即有4078bytes(4kb-18)內(nèi)存空間被閑置浪費(fèi)了。

    #include <stdio.h> #include <string.h> #include <stdlib.h> #include <ctype.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> ? int main(int argc, char *argv[]) { int fd, len; char *buf; char *fname = "/tmp/file_mmap"; ssize_t ret; struct stat sb; ? fd = open(fname, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR); if (fd == -1) { perror("open"); return 1; } if (fstat(fd, &sb) == -1) { perror("stat"); return 1; } ? buf = malloc(sb.st_size); if (buf == NULL) { perror("malloc"); return 1; } ret = read(fd, buf, sb.st_size); for (len = 0; len < sb.st_size; ++len) { buf[len] = toupper(buf[len]); /*putchar(buf[len]);*/ } ? lseek(fd, 0, SEEK_SET); ret = write(fd, buf, sb.st_size); if (ret == -1) { perror("error"); return 1; } ? if (close(fd) == -1) { perror("close"); return 1; } free(buf); return 0; } #gcc –o t_rw t_rw.c open("/tmp/file_mmap", O_RDWR|O_CREAT, 0600) = 3 //open, fd=3 fstat64(3, {st_mode=S_IFREG|0644, st_size=18, ...}) = 0 //fstat, 其中文件大小18 brk(0) = 0x9845000 //brk, 返回當(dāng)前中斷點(diǎn) brk(0x9866000) = 0x9866000 //malloc分配內(nèi)存,堆當(dāng)前最后地址 read(3, "www.perfgeeks.com\n", 18) = 18 //read lseek(3, 0, SEEK_SET) = 0 //lseek write(3, "WWW.PERFGEEKS.COM\n", 18) = 18 //write close(3) = 0 //close

    這里通過read()讀取文件內(nèi)容,toupper()后,調(diào)用write()寫回文件。因?yàn)槲募?#xff0c;體現(xiàn)不出read()/write()的缺點(diǎn):頻繁訪問大文件,需要多個(gè)lseek()來確定位置。每次編輯read()/write(),在物理內(nèi)存中的雙份數(shù)據(jù)。當(dāng)然,不可以忽略創(chuàng)建與維護(hù)mmap()數(shù)據(jù)結(jié)構(gòu)的成本。需要注意:并沒有具體測(cè)試mmap vs read/write,即不能一語斷言誰孰誰劣,具體應(yīng)用場(chǎng)景具體評(píng)測(cè)分析。你只是要記住:mmap內(nèi)存映射文件之后,操作內(nèi)存即是操作文件,可以省去不少系統(tǒng)內(nèi)核調(diào)用(lseek, read, write)。

    mmap() vs malloc()

    使用strace調(diào)試的時(shí)候,通常可以看到通過mmap()創(chuàng)建匿名內(nèi)存映射的身影。比如啟用dl(‘a(chǎn)pc.so’)的時(shí)候,就可以看到如下語句。
    mmap2(NULL, 31457280, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0) = 0xb5ce7000 //30M

    通常使用mmap()進(jìn)行匿名內(nèi)存映射,以此來獲取內(nèi)存,滿足一些特別需求。所謂匿名內(nèi)存映射,是指mmap()的時(shí)候,設(shè)置了一個(gè)特殊的標(biāo)志MAP_ANONYMOUS,且fd可以忽略(-1)。某些操作系統(tǒng)(像FreeBSD),不支持標(biāo)志MAP_ANONYMOUS,可以映射至設(shè)備文件/dev/zero來實(shí)現(xiàn)匿名內(nèi)存映射。使用mmap()分配內(nèi)存的好處是頁面已經(jīng)填滿了0,而malloc()分配內(nèi)存后,并沒有初始化,需要通過memset()初始化這塊內(nèi)存。另外,malloc()分配內(nèi)存的時(shí)候,可能調(diào)用brk(),也可能調(diào)用mmap2()。即分配一塊小型內(nèi)存(小于或等于128kb),malloc()會(huì)調(diào)用brk()調(diào)高斷點(diǎn),分配的內(nèi)存在堆區(qū)域,當(dāng)分配一塊大型內(nèi)存(大于128kb),malloc()會(huì)調(diào)用mmap2()分配一塊內(nèi)存,與堆無關(guān),在堆之外。同樣的,free()內(nèi)存映射方式分配的內(nèi)存之后,內(nèi)存馬上會(huì)被系統(tǒng)收回,free()堆中的一塊內(nèi)存,并不會(huì)馬上被系統(tǒng)回收,glibc會(huì)保留它以供下一次malloc()使用。

    這里演示一下malloc()使用brk()和mmap2()。

    /* * file:t_malloc.c */ #include <stdio.h> #include <string.h> #include <stdlib.h>int main(int argc, char *argv) { char *brk_mm, *mmap_mm; ? printf("-----------------------\n"); brk_mm = (char *)malloc(100); memset(brk_mm, '\0', 100); mmap_mm = (char *)malloc(500 * 1024); memset(mmap_mm, '\0', 500*1024); free(brk_mm); free(mmap_mm); printf("-----------------------\n"); ? return 1; } ? #gcc –o t_malloc t_malloc.c #strace ./t_malloc write(1, "-----------------------\n", 24-----------------------) = 24 brk(0) = 0x85ee000 brk(0x860f000) = 0x860f000 //malloc(100) mmap2(NULL, 516096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7702000 //malloc(5kb) munmap(0xb7702000, 516096) = 0 //free(), 5kb write(1, "-----------------------\n", 24-----------------------) = 24

    通過malloc()分別分配100bytes和5kb的內(nèi)存,可以看出其實(shí)分別調(diào)用了brk()和mmap2(),相應(yīng)的free()也是不回收內(nèi)存和通過munmap()系統(tǒng)回收內(nèi)存。

    mmap()共享內(nèi)存,進(jìn)程通信

    內(nèi)存映射mmap()的另一個(gè)外常見的用法是,進(jìn)程通信。相較于管道、消息隊(duì)列方式而言,這種通過內(nèi)存映射的方式效率明顯更高,它不需要任務(wù)數(shù)據(jù)拷貝。這里,我們通過一個(gè)例子來說明mmap()在進(jìn)程通信方面的應(yīng)用。我們編寫二個(gè)程序,分別是master和slave,slave根據(jù)master不同指令進(jìn)行不同的操作。Master與slave就是通過映射同一個(gè)普通文件進(jìn)行通信的。

    /**@file master.c*/ root@liaowq:/data/tmp# cat master.c #include <stdio.h> #include <time.h> #include <stdlib.h> #include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> ? void listen(); ? int main(int argc, char *argv[]) { listen(); return 0; } ? void listen() { int fd; char *buf; char *fname = "/tmp/shm_command"; ? char command; time_t now; ? fd = open(fname, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR); if (fd == -1) { perror("open"); exit(1); } buf = mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (buf == MAP_FAILED) { perror("mmap"); exit(1); } if (close(fd) == -1) { perror("close"); exit(1); } ? *buf = '0'; sleep(2); for (;;) { if (*buf == '1' || *buf == '3' || *buf == '5' || *buf == '7') { if (*buf > '1') printf("%ld\tgood job [%c]\n", (long)time(&now), *buf); (*buf)++; } if (*buf == '9') { break; } sleep(1); } ? if (munmap(buf, 4096) == -1) { perror("munmap"); exit(1); } } ? /* *@file slave.c */ #include <stdio.h> #include <time.h> #include <stdlib.h> #include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> ? void ready(unsigned int t); void job_hello(); void job_smile(); void job_bye(); char get_command(char *buf); void wait(); ? int main(int argc, char *argv[

    總結(jié)

    以上是生活随笔為你收集整理的linux mmap 内存映射【转】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。