第一篇:【武漢華嵌嵌入式培訓】內存分配函數用法小結
內存分配函數用法小結
作者:武漢華嵌嵌入式培訓中心 技術部
一、用戶空間內存分配:malloc、calloc、realloc
1、malloc原型如下:
extern void *malloc(unsigned int num_bytes);功能:
分配長度為num_bytes字節塊。工作機制:
malloc函數的實質體現在,它有一個將可用的內存塊連接為一個長長的列表的所謂空閑鏈表。調用malloc函數時,它沿連接表尋找一個大到足以滿足用戶請求所需要的內存塊。然后,將該內存塊一分為二(一塊的大小與用戶請求的大小相等,另一塊的大小就是剩下的字節)。接下來,將分配給用戶的那塊內存傳給用戶,并將剩下的那塊(如果有的話)返回到連接表上。
2、calloc原型如下:
void *calloc(unsigned n,unsigned size);功能:
在內存的動態存儲區中分配n個長度為size的連續空間。
3、realloc原型如下:
extern void *realloc(void *mem_address, unsigned int newsize);功能:
先按照newsize指定的大小分配空間,將原有數據從頭到尾拷貝到新分配的內存區域,而后釋放原來mem_address所指內存區域,同時返回新分配的內存區域的首地址。即重新分配存儲器塊的地址。
注意:malloc和calloc的區別:
calloc在動態分配完內存后,自動初始化該內存空間為零,而malloc不初始化,里邊數據是隨機的垃圾數據。
realloc注意事項:
a、realloc失敗的時候,返回NULL。
b、realloc失敗的時候,原來的內存不改變,不會釋放也不會移動。
c、假如原來的內存后面還有足夠多剩余內存的話,realloc的內存等于原來的內存加上剩余內存,realloc還是返回原來內存的地址;假如原來的內存后面沒有足夠多剩余內存的話,realloc將申請新的內存,然后把原來的內存數據拷貝到新內存里,原來的內存將被free掉,realloc返回新內存的地址。
d、如果size為0,效果等同于free()。
e、傳遞給realloc的指針必須是先前通過malloc(), calloc(), 或realloc()分配的。
f、傳遞給realloc的指針可以為空,等同于malloc。
以上三者的事例代碼如下: #include
int main(){
//最好每次內存申請都檢查申請是否成功
//下面這段僅僅作為演示的代碼沒有檢查
char *pt1;char *pt2;char *pt3;
pt1 =(char *)malloc(sizeof(char)*10);printf(“pt1 = %pn”, pt1);//以下可能會輸出亂碼,說明malloc分配的空間沒有被初始化為0 printf(“%sn”, pt1);scanf(“%s”, pt1);
pt2 =(char *)calloc(10,sizeof(char));printf(“pt2 = %pn”, pt2);//以下輸出為空,說明calloc分配的空間被初始化為0 printf(“%sn”, pt2);
pt3 =(char *)realloc(pt1, sizeof(char)*20);printf(“pt3 = %pn”, pt3);//以下輸出pt1中原先的內容。printf(“%sn”, pt3);
//以下是釋放申請的內存空間 free(pt2);free(pt3);return 0;
}
二、內核空間內存分配:kmalloc、vmalloc 對于提供了MMU(存儲管理器,輔助操作系統進行內存管理,提供虛實地址轉換等硬件支持)的處理器而言,Linux提供了復雜的存儲管理系統,使得進程所能訪問的內存達到4GB。
進程的4GB內存空間被人為的分為兩個部分--用戶空間與內核空間。用戶空間地址分布從0到3GB(PAGE_OFFSET,在0x86中它等于0xC0000000),3GB到4GB為內核空間。
從前面的介紹已經看出,這兩個函數所分配的內存都處于內核空間,即從3GB~4GB;但位置不同,kmalloc()分配的內存處于3GB~high_memory之間,這一段內核空間與物理內存的映射一一對應,而vmalloc()分配的內存在vmalloc_start~4GB之間,這一段連續內存區映射到物理內存也可能是非連續的。
vmalloc()工作方式與kmalloc()類似,其主要差別在于前者分配的物理地址無需連續,而后者確保頁在物理上是連續的(虛地址自然也是連續的)。盡管僅僅在某些情況下才需要物理上連續的內存塊,但是,很多內核代碼都調用kmalloc(),而不是用vmalloc()獲得內存。這主要是出于性能的考慮。vmalloc()函數為了把物理上不連續的頁面轉換為虛擬地址空間上連續的頁,必須專門建立頁表項。還有,通過vmalloc()獲得的頁必須一個一個的進行映射(因為它們物理上不是連續的),這就會導致比直接內存映射大得多的緩沖區刷新。因為這些原因,vmalloc()僅在絕對必要時才會使用——典型的就是為了獲得大塊內存時,例如,當模塊被動態插入到內核中時,就把模塊裝載到由vmalloc()分配的內存上。
kamlloc函數原型: #include
(2)第二個參數是分配標志(flags),他提供了多種kmalloc的行為。
vamlloc函數原型:
#include
我們用下面的程序來演示kmalloc和vmalloc的區別: #include
//最好每次內存申請都檢查申請是否成功
//下面這段僅僅作為演示的代碼沒有檢查
kmallocmem =(unsigned char*)kmalloc(100, 0);
printk(“<1>kmallocmem addr=%x”, kmallocmem);
vmallocmem =(unsigned char*)vmalloc(1000000);
printk(“<1>vmallocmem addr=%x”, vmallocmem);
return 0;} void __exit mem_module_exit(void){
kfree(kmallocmem);
vfree(vmallocmem);} module_init(mem_module_init);module_exit(mem_module_exit);總結:
a、kmalloc和vmalloc分配的是內核的內存,malloc分配的是用戶的內存。b、kmalloc保證分配的內存在物理上是連續的, kmalloc()分配的內存在0xBFFFFFFF-0xFFFFFFFF以上的內存中,driver一般是用它來完成對DS的分配,更適合于類似設備驅動的程序來使用。
c、vmalloc保證的是在虛擬地址空間上的連續,vmalloc()則是位于物理地址非連續,虛地址連續區,起始位置由VMALLOL_START來決定,一般作為交換區、模塊的分配。
d、kmalloc能分配的大小有限,vmalloc和malloc能分配的大小相對較大(因為vmalloc還可以處理交換空間)。
e、內存只有在要被DMA訪問的時候才需要物理上連續,vmalloc比kmalloc要慢。
f、vmalloc使用的正確場合是分配一大塊,連續的,只在軟件中存在的,用于緩沖的內存區域。不能在微處理器之外使用。
g、vmalloc 中調用了kmalloc(GFP—KERNEL),因此也不能應用于原子上下文。
hkmalloc和kfree管理內核段內分配的內存,這是真實地址已知的實際物理內存塊。
i、vmalloc對應于vfree,分配連續的虛擬內存,但是物理上不一定連續。j、kmalloc分配內存是基于slab,因此slab的一些特性包括著色,對齊等都具備,性能較好。物理地址和邏輯地址都是連續的。
第二篇:【武漢華嵌嵌入式培訓中心】Linux進程間通信之消息隊列
Linux進程間通信之消息隊列
作者:武漢華嵌嵌入式培訓中心 技術部
在linux下有兩種消息隊列,一種是POSIX的消息隊列,另外一種是System V消息隊列。在這里只講System V隊列的使用。System V消息隊列使用消息隊列標識符標識,在某個進程往一個隊列中寫入一個消息之前,不求另外某個進程正在等待該隊列上一個消息的到達。
對于系統中每個消息隊列,內核維護一個定義在
消息隊列由內核進行維護,我們可以將內核中某個選定的消息隊列畫為一個消息鏈表,如下圖所示:
以下都是操作消息隊列的API函數,在這里將對其一一講解。
? 創建一個消息隊列。
#include
該函數在執行正常返回時,返回的是一個整數標識符,其他三個函數就用它來指代該隊列。該標識符是基于指定的key產生的,而key即可以是ftok的返回值,也可以是常值IPC_PRIVATE。
oflag可以是讀寫權限的值的組合,它還可以與IPC_CREAT或IPC_CREAT|IPC_EXCL按位或。
當創建一個新消息隊列時,msqid_ds結構的一些成員被初始化。
? 往一個打開的消息隊列上放置一個消息。
#include
? 使用msgrcv函數從某個消息隊列中讀出一個消息。
#include
其中ptr參數指定所接收消息的存放位置,和msgsnd一個,該指針指向緊挨在真正的消息數據之前返回的長整數類型字段。Length指定了由ptr指向的緩沖區中數據部分的大小,這是該函數能返回的最大數據量,該長度不包含
消息類型占的字節數。type指定希望從消息隊列中讀出什么類型的消息,type以下的幾種取值有不同的效果,如下:
⑴、type為0時,則返回隊列中的第一個消息,也就是最早的那個消息。⑵、type為大于0時,則返回其類型值為type的第一個消息。
⑶、type為小于0時,則返回其類型值小于或等于type參數的絕對值的消息中類型最小的第一個消息。flag的可能取值同msgsnd一樣,代表著同樣的意思。只不過msgrcv多了一個選擇,那就是MSG_NOERROR,如果設置了該位,當所接收消息的真正數據部分大于length參數時,msgrcv只截短數據部分,面不返回錯誤。該函數成功返回時,msgrcv返回的是所接收消息中數據的字節數。它不包括消息類型所占有字節數。
? 使用msgctl對消息隊列進行控制。
#include
IPC_RMID 從系統中刪除由msqid指定的消息隊列,對于該命令,msgctl第三個參
數被忽略。
IPC_SET 給所指定的消息隊列設置其msqid_ds結構的幾個成員。IPC_STAT 給調用者返回與所指定消息隊列對應的當前msqid_ds結構。
總結:
? 消息隊列是由內核維護的,也就是說消息隊列是隨內核持續性的。在進程結束的時候,消息隊列并消失,只有在顯示的刪除消息隊列或者在內核自檢的時候,消息隊列才會刪除。
以下是使用消息隊列例子:
? 發送進程:
#include
#define MAX_MSG_LENGTH 1024 //自己定義的消息格式 typedef struct msgbuf { long types;char texts[MAX_MSG_LENGTH];}SYS_MSG;
int main(){ int msgid;key_t key;int retval;SYS_MSG mybuf;
if((key = ftok(“/”, 4))< 0){ perror(“ftok”);}
if((msgid = msgget(key, IPC_CREAT|0777))< 0){ perror(“msgget”);}
mybuf.types = 1;strcpy(mybuf.texts, “hello world”);if((msgsnd(msgid, &mybuf, MAX_MSG_LENGTH, 0)))//的消息。{ perror(“msgsnd”);}
mybuf.types = 2;strcpy(mybuf.texts, “how are you”);if((msgsnd(msgid, &mybuf, MAX_MSG_LENGTH, 0)))//的消息。{ perror(“msgsnd”);
發送消息類型為1發送消息類型為2
}
mybuf.types = 3;strcpy(mybuf.texts, “i'm fine”);if((msgsnd(msgid, &mybuf, MAX_MSG_LENGTH, 0)))//發送消息類型為3的消息。{ perror(“msgsnd”);}
return 0;} ? 接收進程:
#include
#define MAX_MSG_LENGTH 5 typedef struct msgbuf {
long types;char texts[MAX_MSG_LENGTH];}SYS_MSG;
int main(){ int msgid;key_t key;int retval;SYS_MSG mybuf;
if((key = ftok(“/”, 4))< 0){ perror(“ftok”);}
if((msgid = msgget(key, IPC_CREAT|0777))< 0){ perror(“msgget”);} while(1){ //輸入想接收的消息類型
scanf(“%ld”, &mybuf.types);memset(mybuf.texts, 0, MAX_MSG_LENGTH);
if(0 == mybuf.types){ break;}
//接收消息類型為上面輸入的消息類型
if((msgrcv(msgid, &mybuf, MAX_MSG_LENGTH, mybuf.types, MSG_NOERROR))< 0){ perror(“msgrcv”);}
printf(“msgrcv : %sn”, mybuf.texts);}
if((msgctl(msgid, IPC_RMID, NULL))< 0)//從內核中刪除消息隊列 { perror(“msgctl”);}
return 0;
}