Unix/Linux环境C编程入门教程(27) 内存那些事儿
calloc(配置內存空間) | |
相關函數 | malloc,free,realloc,brk |
表頭文件 | #include <stdlib.h> |
定義函數 | void *calloc(size_t nmemb,size_t size); |
函數說明 | calloc()用來配置nmemb個相鄰的內存單位,每一單位的大小為size,并返回指向第一個元素的指針。這和使用下列的方式效果相同:malloc(nmemb*size);不過,在利用calloc()配置內存時會將內存內容初始化為0。 |
返回值 | 若配置成功則返回一指針,失敗則返回NULL。 |
范例 | /* 動態配置10個struct test 空間*/ |
? | |
| |
相關函數 | malloc,calloc,realloc,brk |
表頭文件 | #include<stdlib.h> |
定義函數 | void free(void *ptr); |
函數說明 | 參數ptr為指向先前由malloc()、calloc()或realloc()所返回的內存指針。調用free()后ptr所指的內存空間便會被收回。假若參數ptr所指的內存空間已被收回或是未知的內存地址,則調用free()可能會有無法預期的情況發生。若參數ptr為NULL,則free()不會有任何作用。 |
? | |
| |
相關函數 | sbrk |
表頭文件 | #include<unistd.h> |
定義函數 | size_t getpagesize(void); |
函數說明 | 返回一分頁的大小,單位為字節(byte)。此為系統的分頁大小,不一定會和硬件分頁大小相同。 |
返回值 | 內存分頁大小。附加說明在Intel x86 上其返回值應為4096bytes。 |
范例 | #include <unistd.h> |
? | |
| |
相關函數 | calloc,free,realloc,brk |
表頭文件 | #include<stdlib.h> |
定義函數 | void * malloc(size_t size); |
函數說明 | malloc()用來配置內存空間,其大小由指定的size決定。 |
返回值 | 若配置成功則返回一指針,失敗則返回NULL。 |
范例 | void p = malloc(1024); /*配置1k的內存*/ |
? | |
相關函數 | munmap,open |
表頭文件 | #include <unistd.h> |
定義函數 | void *mmap(void *start,size_t length,int prot,int flags,int fd,off_t offsize); |
函數說明 | mmap()用來將某個文件內容映射到內存中,對該內存區域的存取即是直接對該文件內容的讀寫。參數start指向欲對應的內存起始地址,通常設為NULL,代表讓系統自動選定地址,對應成功后該地址會返回。參數length代表將文件中多大的部分對應到內存。 |
參數 | prot代表映射區域的保護方式有下列組合 |
參數 | flags會影響映射區域的各種特性 |
返回值 | 若映射成功則返回映射區的內存起始地址,否則返回MAP_FAILED(-1),錯誤原因存于errno 中。 |
錯誤代碼 | EBADF 參數fd 不是有效的文件描述詞 |
? | |
| |
相關函數 | mmap |
表頭文件 | #include<unistd.h> |
定義函數 | int munmap(void *start,size_t length); |
函數說明 | munmap()用來取消參數start所指的映射內存起始地址,參數length則是欲取消的內存大小。當進程結束或利用exec相關函數來執行其他程序時,映射內存會自動解除,但關閉對應的文件描述詞時不會解除映射。 |
返回值 | 如果解除映射成功則返回0,否則返回-1,錯誤原因存于errno中錯誤代碼EINVAL |
參數 | start或length 不合法。 |
范例 | 參考mmap() |
- 文件的概念
大多數資源,Linux都是以文件的方式來訪問。
Linux中主要的文件類型分為4種:普通文件、目錄文件、鏈接文件和設備文件
Linux中的文件屬性:
-rwx rwx rwx
首先,Linux中文件的擁有者可以把文件的訪問屬性設成3種不同的訪問權限:可讀(r)、可寫(w)和可執行(x)。
文件又有3種不同的用戶級別:文件擁有者(u)、所屬的用戶組(g)和系統里的其他用戶(o)
第一個字符顯示文件的類型:
"-"表示普通文件
"d"表示目錄文件
"l"表示鏈接文件
"c"表示字符設備
"b"表示塊設備
"p"表示命名管道比如FIFO文件
"f"表示堆棧文件比如LILO文件
第一個字符之后的3個三位字符組:
第一個三位字符組表示文件擁有者(u)對該文件的權限
第二個三位字符組表示文件用戶組(g)對該文件的權限
第三個三位字符組表示系統其他用戶(o)對該文件的權限
若該用戶組對此沒有權限,一般顯示"-"字符
如圖所示:
- 文件描述符。
文件描述符是個很小的正整數,它是一個索引值,指向內核為每個進程所維護的該進程打開文件的記錄表。
實際上,內存映射機制并不是完全為了共享內存的目的而設計的,它本身提供了不同于一般普通文件的訪問方式,進程可以像訪問內存一樣對普通文件進程操作.而POSIX或System V共享內存IPC則純粹是用于共享內存的目的.當然內存映射實現共享內存,也是內存映射的應用之一
內存映射機制的用途: A、以訪問內存的方式讀寫文件; B、實現共享內存;
?
mmap()系統調用:
?? mmap()系統調用使得進程之間通過映射同一個普通文件而實現共享內存的目的.普通文件被映射到進程的地址空間之后,進程就可以像訪問普通內存一樣對文件進行訪問,不必再調用read()、write()等系統調用操作.
?? mmap()系統調用介紹:
?? void* mmap(void* addr, size_t len, int prot, int flags, int fd, off_t offset);
?? 該函數在進程的地址空間與文件對象或共享內存對象之間建立一種映射關系;
?? addr? :該參數指定文件應該被映射到進程地址空間的起始地址,一般被指定為一個空指針,此時,程序把選擇起始地址的任務留給內核來完成了.這個地址是進程地址空間中需要映射到文件中的內存區域的首地址;也就是說,在進程地址空間中用于文件映射的內存區域的首地址;
?? len?? :文件被映射到調用進程的地址空間中的字節數,它從被映射文件開頭offset個字節處開始算起,取len個字節,把文件中的這len個字節的文件空間映射到進程的地址空間中;
?? port? :指定文件被映射到內存中之后的訪問權限.可取的值有:PORT_READ(可讀)、PORT_WRITE(可寫)、PORT_EXEC(可執行)、PORT_NONE(不可訪問);
?? flags :映射標記;取值如下:MAP_SHARED、MAP_PRIVATE、MAP_FIXED,其中,MAP_SHARED和MAP_PRIVATE必選其一,而MAP_FIXED則不推薦使用;
?? fd??? :即將被映射到進程地址空間中的文件的描述符.一般由系統調用open()返回;同時,fd可以指定為-1,此時,必須指定flags參數中的MAP_ANON,表明進程的是匿名映射(不涉及具體的文件名,避免了文件的創建及打開,很顯然,只能用于具有親屬關系的進程之間的通信).
?? offset:從文件開頭計算offset個字節處開始映射;也就是,文件中需要被映射的文件內容的起始地址,這個起始地址的計算是以文件開頭為參照的;這個參數一般取值為0,表示從文件開頭處開始映射;
?? 返回值:文件最終映射到進程地址空間中的起始地址;進程可直接以該地址為有效的起始地址進行操作;也就是文件中開始映射的起始字節點到進程中對應映射內存區的起始地址點處的一個映射;換句話就是說,在進程地址空間中用于文件映射的內存區域的首地址;
系統調用mmap()用于共享內存的兩種方式:
?? A、使用普通文件提供的內存映射/共享內存:適用于任何進程之間;此時,需要使用系統調用open()事先打開或創建一個文件,然后再調用mmap():
????? fd = open(filename, flag, mode);
????? ......
????? ptr = mmap(NULL, len, PORT_READ|PORT_WRITE, MAP_SHARED, fd, 0);
?????五、解除內存映射關系:
?? 當進程間通信結束時,需要解除文件頁面空間到進程地址空間之間的映射關系;也就說,進程通信結束時,需要把掛載到進程地址空間上的文件卸載下來;這個任務由系統調用munmap();
?? int munmap(void* addr, size_t len);
?? 該系統調用用于在進程地址空間中結束映射關系;
?? addr:是調用mmap()返回的進程地址空間中用于文件映射的內存區域的首地址;
?? len :進程地址空間中映射區域的大小,單位:字節;
?? 當映射關系解除之后,對原來映射地址的訪問將導致段錯誤發生;
?? 返回值: -1:失敗; 0:成功;
內存映射的同步:
?? 一般來說,進程在映射空間中對共享內容的修改并不會直接寫回到磁盤文件中,可以通過調用msync()來實現磁盤上文件內容與共享內存區中的內容與一致
整體流程就是:
源代碼:
#include <stdio.h> #include <unistd.h> #include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h>#include <string.h> int main() { int fd;//文件描述符 char *start = NULL,*flag = NULL;//指針接收文件影射的開始地址 struct stat st; printf("page size = %d\n",getpagesize( ) ); fd=open("read.log",O_RDONLY); /*打開/etc/passwd*/ if(fd < -1) //打開失敗 return -1; printf("打開成功\n"); fstat(fd,&st); /*取得文件大小*/ start =(char *) malloc(st.st_size+1); if(start == NULL) return -1; printf("內存分配成功\n"); flag=mmap(start,st.st_size,PROT_READ,MAP_PRIVATE,fd,0); /*私有不共享*/ if(flag == MAP_FAILED && start != flag) /*判斷是否映射成功*/ return -1; printf("映射成功\n");printf("%s",flag); memcpy(start,flag,st.st_size); printf("輸出完成\n"); munmap(start,st.st_size); /*解除映射*/ printf("解除映射完畢\n");return 0; }首先創建testmem.c
再創建read.log
在RHEL7上的運行情況
在RHEL6上
在MAC上
?
在Solaris上
先進入桌面
將兩個文件都拷貝過來
轉載于:https://www.cnblogs.com/niulanshan/p/6174851.html
總結
以上是生活随笔為你收集整理的Unix/Linux环境C编程入门教程(27) 内存那些事儿的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 扫雷游戏制作学习过程
- 下一篇: Linux 关机命令详解 转自脚本之家