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都是以檔案的方式來訪問。
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()來實現磁碟上檔案內容與共享記憶體區中的內容與一致 - 小試牛刀
整體流程就是:
- 首先開啟一個檔案,讀取出檔案資訊
- 根據檔案長度分配相應長度的堆記憶體
- Mmap函式做記憶體對映
- 從記憶體對映中開始拷貝內容
- 輸出函式返回的地址開始的內容
- 輸出完畢之後關閉記憶體對映檔案
- 輸出拷貝的檔案
- 釋放記憶體
- 關閉檔案描述符
原始碼:
#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上
先進入桌面
將兩個檔案都拷貝過來
相關文章
- Unix/Linux環境C程式設計入門教程(29) 記憶體操作那些事兒LinuxC程式程式設計記憶體
- Unix/Linux環境C程式設計入門教程(30) 字串操作那些事兒LinuxC程式程式設計字串
- Unix/Linux環境C程式設計入門教程(28) 日期時間那些事兒LinuxC程式程式設計
- Unix/Linux環境C程式設計入門教程(33) 命令和滑鼠管理使用者和組LinuxC程式程式設計
- Unix/Linux環境C程式設計入門教程(31) 數學函式帶你戰勝企業面試LinuxC程式程式設計函式面試
- 趣科技:程式設計師那些事兒程式設計師
- 程式設計師兼職那些事兒程式設計師
- iOS記憶體管理的那些事兒-原理及實現iOS記憶體
- 辭職的程式設計師那些事兒程式設計師
- 談談java入門的那些事兒Java
- GC那些事兒–Android記憶體優化第一彈GCAndroid記憶體優化
- GC那些事兒--Android記憶體優化第一彈GCAndroid記憶體優化
- 程式設計師招聘和麵試那些事兒程式設計師
- ABAP開發環境語法高亮的那些事兒開發環境
- JVM 記憶體的那些事JVM記憶體
- JVM記憶體的那些事JVM記憶體
- C語言那些事兒C語言
- 程式程式設計1 – Unix環境高階程式設計7章讀書筆記程式設計筆記
- 程式程式設計2 – Unix環境高階程式設計8章讀書筆記程式設計筆記
- unix環境高階程式設計(中)-程式篇程式設計
- Shell入門:掌握Linux,OS X,Unix的Shell環境Linux
- 程式設計師的那些事兒 -- 高階程式設計師買衣服程式設計師
- Spark MLlib 入門學習筆記 - 程式設計環境配置Spark筆記程式設計
- UNIX訊號(signal)程式設計 - UNIX高階環境程式設計第10章讀書筆記程式設計筆記
- linux環境下的c++程式設計LinuxC++程式設計
- 程式程式設計3 - UNIX高階環境程式設計第9章讀書筆記程式設計筆記
- 軟體測試中過度設計的那些事兒
- 小程式那些事-入門篇
- 程式設計入門18:Python生產環境程式設計Python
- UNIX系統程式設計的瑞士軍刀 --《UNIX環境高階程式設計》書評程式設計
- C#程式設計基礎入門教程pdfC#程式設計
- MVP那些事兒(7)……Repository設計分析MVP
- 設定linux/unix的shell環境Linux
- 虛擬記憶體的那點事兒記憶體
- 程式設計師的那些事兒 -- 皆大歡喜的加薪程式設計師
- unix環境高階程式設計(上)-檔案篇程式設計
- 程式碼重構那些事兒
- UNIX共享記憶體的程式(轉)記憶體