武漢電腦培訓(xùn)資訊:【武漢華嵌】?jī)?nèi)存分配函數(shù)用法小結(jié)

武漢
當(dāng)前位置:求學(xué)問校網(wǎng)首頁>武漢資訊>武漢電腦培訓(xùn)資訊

【武漢華嵌】?jī)?nèi)存分配函數(shù)用法小結(jié)

來源:求學(xué)問校網(wǎng)     發(fā)表時(shí)間:2011-10-26     瀏覽 52

作者:武漢華嵌技術(shù)部

 

一、用戶空間內(nèi)存分配:malloc、calloc、realloc

1、malloc原型如下:

extern void *malloc(unsigned int num_bytes);

功能:

分配長(zhǎng)度為num_bytes字節(jié)塊。

工作機(jī)制:

malloc函數(shù)的實(shí)質(zhì)體現(xiàn)在,它有一個(gè)將可用的內(nèi)存塊連接為一個(gè)長(zhǎng)長(zhǎng)的列表的所謂空閑鏈表。調(diào)用malloc函數(shù)時(shí),它沿連接表尋找一個(gè)大到足以滿足用戶請(qǐng)求所需要的內(nèi)存塊。然后,將該內(nèi)存塊一分為二(一塊的大小與用戶請(qǐng)求的大小相等,另一塊的大小就是剩下的字節(jié))。接下來,將分配給用戶的那塊內(nèi)存?zhèn)鹘o用戶,并將剩下的那塊(如果有的話)返回到連接表上。

 

2、calloc原型如下:

void *calloc(unsigned n,unsigned size);

功能:

在內(nèi)存的動(dòng)態(tài)存儲(chǔ)區(qū)中分配n個(gè)長(zhǎng)度為size的連續(xù)空間。

 

3、realloc原型如下:

extern void *realloc(void *mem_address, unsigned int newsize);

功能:

先按照newsize指定的大小分配空間,將原有數(shù)據(jù)從頭到尾拷貝到新分配的內(nèi)存區(qū)域,而后釋放原來mem_address所指內(nèi)存區(qū)域,同時(shí)返回新分配的內(nèi)存區(qū)域的首地址。即重新分配存儲(chǔ)器塊的地址。

 

注意:malloc和calloc的區(qū)別:

calloc在動(dòng)態(tài)分配完內(nèi)存后,自動(dòng)初始化該內(nèi)存空間為零,而malloc不初始化,里邊數(shù)據(jù)是隨機(jī)的垃圾數(shù)據(jù)。

 

realloc注意事項(xiàng):

  a、realloc失敗的時(shí)候,返回NULL。

  b、realloc失敗的時(shí)候,原來的內(nèi)存不改變,不會(huì)釋放也不會(huì)移動(dòng)。

  c、假如原來的內(nèi)存后面還有足夠多剩余內(nèi)存的話,realloc的內(nèi)存等于原來的內(nèi)存加上剩余內(nèi)存,realloc還是返回原來內(nèi)存的地址; 假如原來的內(nèi)存后面沒有足夠多剩余內(nèi)存的話,realloc將申請(qǐng)新的內(nèi)存,然后把原來的內(nèi)存數(shù)據(jù)拷貝到新內(nèi)存里,原來的內(nèi)存將被free掉,realloc返回新內(nèi)存的地址。

  d、如果size為0,效果等同于free()。

  e、傳遞給realloc的指針必須是先前通過malloc(), calloc(), 或realloc()分配的。

f、傳遞給realloc的指針可以為空,等同于malloc。

 

以上三者的事例代碼如下:

#include <stdio.h>

#include <malloc.h>

#include <string.h>

 

int main()

{

  //最好每次內(nèi)存申請(qǐng)都檢查申請(qǐng)是否成功

  //下面這段僅僅作為演示的代碼沒有檢查

      char *pt1;

      char *pt2;

      char *pt3;

     

      pt1 = (char *)malloc(sizeof(char)ၲ);

      printf("pt1 = %p\n", pt1);

      //以下可能會(huì)輸出亂碼,說明malloc分配的空間沒有被初始化為0

      printf("%s\n", pt1);

      scanf("%s", pt1);

     

      pt2 = (char *)calloc(10,sizeof(char));

      printf("pt2 = %p\n", pt2);

      //以下輸出為空,說明calloc分配的空間被初始化為0

      printf("%s\n", pt2);    

 

      pt3 = (char *)realloc(pt1, sizeof(char)ၼ);

      printf("pt3 = %p\n", pt3);

      //以下輸出pt1中原先的內(nèi)容。

      printf("%s\n", pt3);

 

      //以下是釋放申請(qǐng)的內(nèi)存空間

      free(pt2);

      free(pt3);

      return 0;

}

 

二、內(nèi)核空間內(nèi)存分配:kmalloc、vmalloc

       對(duì)于提供了MMU(存儲(chǔ)管理器,輔助操作系統(tǒng)進(jìn)行內(nèi)存管理,提供虛實(shí)地址轉(zhuǎn)換等硬件支持)的處理器而言,Linux提供了復(fù)雜的存儲(chǔ)管理系統(tǒng),使得進(jìn)程所能訪問的內(nèi)存達(dá)到4GB。

進(jìn)程的4GB內(nèi)存空間被人為的分為兩個(gè)部分--用戶空間與內(nèi)核空間。用戶空間地址分布從0到3GB(PAGE_OFFSET,在0x86中它等于0xC0000000),3GB到4GB為內(nèi)核空間。

從前面的介紹已經(jīng)看出,這兩個(gè)函數(shù)所分配的內(nèi)存都處于內(nèi)核空間,即從3GB~4GB;但位置不同,kmalloc()分配的內(nèi)存處于3GB~high_memory之間,這一段內(nèi)核空間與物理內(nèi)存的映射一一對(duì)應(yīng),而vmalloc()分配的內(nèi)存在vmalloc_start~4GB之間,這一段連續(xù)內(nèi)存區(qū)映射到物理內(nèi)存也可能是非連續(xù)的。

   vmalloc()工作方式與kmalloc()類似,其主要差別在于前者分配的物理地址無需連續(xù),而后者確保頁在物理上是連續(xù)的(虛地址自然也是連續(xù)的)。

盡管僅僅在某些情況下才需要物理上連續(xù)的內(nèi)存塊,但是,很多內(nèi)核代碼都調(diào)用kmalloc(),而不是用vmalloc()獲得內(nèi)存。這主要是出于性能的考慮。vmalloc()函數(shù)為了把物理上不連續(xù)的頁面轉(zhuǎn)換為虛擬地址空間上連續(xù)的頁,必須專門建立頁表項(xiàng)。還有,通過vmalloc()獲得的頁必須一個(gè)一個(gè)的進(jìn)行映射(因?yàn)樗鼈兾锢砩喜皇沁B續(xù)的),這就會(huì)導(dǎo)致比直接內(nèi)存映射大得多的緩沖區(qū)刷新。因?yàn)檫@些原因,vmalloc()僅在絕對(duì)必要時(shí)才會(huì)使用——典型的就是為了獲得大塊內(nèi)存時(shí),例如,當(dāng)模塊被動(dòng)態(tài)插入到內(nèi)核中時(shí),就把模塊裝載到由vmalloc()分配的內(nèi)存上。

kamlloc函數(shù)原型:

#include<linux/slab.h>

void *kmalloc(size_t size, int flags);

(1)第一個(gè)參數(shù)是要分配的塊的大小

(2)第二個(gè)參數(shù)是分配標(biāo)志(flags),他提供了多種kmalloc的行為。

 

vamlloc函數(shù)原型:

#include <linux/vmalloc.h>
void *vmalloc(unsigned long size);

(1)第一個(gè)參數(shù)是要分配的塊的大小

 

我們用下面的程序來演示kmalloc和vmalloc的區(qū)別:

#include <linux/module.h>

#include <linux/slab.h>

#include <linux/vmalloc.h>

MODULE_LICENSE("GPL");

unsigned char *kmallocmem;

unsigned char *vmallocmem;

int __init mem_module_init(void)

{

  //最好每次內(nèi)存申請(qǐng)都檢查申請(qǐng)是否成功

  //下面這段僅僅作為演示的代碼沒有檢查

  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);

 

總結(jié):

a、kmalloc和vmalloc分配的是內(nèi)核的內(nèi)存,malloc分配的是用戶的內(nèi)存。

b、kmalloc保證分配的內(nèi)存在物理上是連續(xù)的, kmalloc()分配的內(nèi)存在0xBFFFFFFF-0xFFFFFFFF以上的內(nèi)存中,driver一般是用它來完成對(duì)DS的分配,更適合于類似設(shè)備驅(qū)動(dòng)的程序來使用。

c、vmalloc保證的是在虛擬地址空間上的連續(xù),vmalloc()則是位于物理地址非連續(xù),虛地址連續(xù)區(qū),起始位置由VMALLOL_START來決定,一般作為交換區(qū)、模塊的分配。

d、kmalloc能分配的大小有限,vmalloc和malloc能分配的大小相對(duì)較大(因?yàn)関malloc還可以處理交換空間)。

e、內(nèi)存只有在要被DMA訪問的時(shí)候才需要物理上連續(xù),vmalloc比kmalloc要慢。

f、vmalloc使用的正確場(chǎng)合是分配一大塊,連續(xù)的,只在軟件中存在的,用于緩沖的內(nèi)存區(qū)域。不能在微處理器之外使用。

g、vmalloc 中調(diào)用了kmalloc (GFP—KERNEL),因此也不能應(yīng)用于原子上下文。

hkmalloc和kfree管理內(nèi)核段內(nèi)分配的內(nèi)存,這是真實(shí)地址已知的實(shí)際物理內(nèi)存塊。

i、vmalloc對(duì)應(yīng)于vfree,分配連續(xù)的虛擬內(nèi)存,但是物理上不一定連續(xù)。

j、kmalloc分配內(nèi)存是基于slab,因此slab的一些特性包括著色,對(duì)齊等都具備,性能較好。物理地址和邏輯地址都是連續(xù)的。