malloc/new函数及malloc()的一种简单原理性实现
malloc函數(shù)
void *malloc(int size);說(shuō)明:malloc 向系統(tǒng)申請(qǐng)分配指定size個(gè)字節(jié)的內(nèi)存空間。返回類型是 void* 類型。void* 表示未確定類型的指針。C,C++規(guī)定,void* 類型可以強(qiáng)制轉(zhuǎn)換為任何其它類型的指針。
malloc 與free 是C++/C 語(yǔ)言的標(biāo)準(zhǔn)庫(kù)函數(shù),new/delete 是C++的運(yùn)算符。它們都可用于申請(qǐng)動(dòng)態(tài)內(nèi)存和釋放內(nèi)存。對(duì)于非內(nèi)部數(shù)據(jù)類型的對(duì)象而言,光用maloc/free 無(wú)法滿足動(dòng)態(tài)對(duì)象的要求。對(duì)象在創(chuàng)建的同時(shí)要自動(dòng)執(zhí)行構(gòu)造函數(shù), 對(duì)象在消亡之前要自動(dòng)執(zhí)行析構(gòu)函數(shù)。由于malloc/free 是庫(kù)函數(shù)而不是運(yùn)算符,不在編譯器控制權(quán)限之內(nèi),不能夠把執(zhí)行構(gòu)造函數(shù)和析構(gòu)函數(shù)的任務(wù)強(qiáng)加于malloc/free。因此C++語(yǔ)言需要一個(gè)能完成動(dòng)態(tài)內(nèi)存分配和初始化工作的運(yùn)算符new,以及一個(gè)能完成清理與釋放內(nèi)存工作的運(yùn)算符delete。注意new/delete 不是庫(kù)函數(shù)。
?
malloc()是C語(yǔ)言中動(dòng)態(tài)存儲(chǔ)管理的一組標(biāo)準(zhǔn)庫(kù)函數(shù)之一。其作用是在內(nèi)存的動(dòng)態(tài)存儲(chǔ)區(qū)中分配一個(gè)長(zhǎng)度為size的連續(xù)空間。其參數(shù)是一個(gè)無(wú)符號(hào)整形數(shù),返回值是一個(gè)指向所分配的連續(xù)存儲(chǔ)域的起始地址的指針.
malloc()工作機(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é))。接下來(lái),將分配給用戶的那塊內(nèi)存?zhèn)鹘o用戶,并將剩下的那塊(如果有的話)返回到連接表上。調(diào)用free函數(shù)時(shí),它將用戶釋放的內(nèi)存塊連接到空閑鏈上。到最后,空閑鏈會(huì)被切成很多的小內(nèi)存片段,如果這時(shí)用戶申請(qǐng)一個(gè)大的內(nèi)存片段,那么空閑鏈上可能沒(méi)有可以滿足用戶要求的片段了。于是,malloc函數(shù)請(qǐng)求延時(shí),并開(kāi)始在空閑鏈上翻箱倒柜地檢查各內(nèi)存片段,對(duì)它們進(jìn)行整理,將相鄰的小空閑塊合并成較大的內(nèi)存塊。?
malloc()在操作系統(tǒng)中的實(shí)現(xiàn)
在 C 程序中,多次使用malloc () 和 free()。不過(guò),您可能沒(méi)有用一些時(shí)間去思考它們?cè)谀牟僮飨到y(tǒng)中是如何實(shí)現(xiàn)的。本節(jié)將向您展示 malloc 和 free 的一個(gè)最簡(jiǎn)化實(shí)現(xiàn)的代碼,來(lái)幫助說(shuō)明管理內(nèi)存時(shí)都涉及到了哪些事情。
在大部分操作系統(tǒng)中,內(nèi)存分配由以下兩個(gè)簡(jiǎn)單的函數(shù)來(lái)處理:
malloc_init 將是初始化內(nèi)存分配程序的函數(shù)。它要完成以下三件事:將分配程序標(biāo)識(shí)為已經(jīng)初始化,找到系統(tǒng)中最后一個(gè)有效內(nèi)存地址,然后建立起指向我們管理的內(nèi)存的指針。這三個(gè)變量都是全局變量:
//清單 1. 我們的簡(jiǎn)單分配程序的全局變量int has_initialized = 0; void *managed_memory_start; void *last_valid_address;如前所述,被映射的內(nèi)存的邊界(最后一個(gè)有效地址)常被稱為系統(tǒng)中斷點(diǎn)或者 當(dāng)前中斷點(diǎn)。在很多 UNIX 系統(tǒng)中,為了指出當(dāng)前系統(tǒng)中斷點(diǎn),必須使用 sbrk(0) 函數(shù)。 sbrk 根據(jù)參數(shù)中給出的字節(jié)數(shù)移動(dòng)當(dāng)前系統(tǒng)中斷點(diǎn),然后返回新的系統(tǒng)中斷點(diǎn)。使用參數(shù) 0 只是返回當(dāng)前中斷點(diǎn)。這里是我們的 malloc 初始化代碼,它將找到當(dāng)前中斷點(diǎn)并初始化我們的變量:
清單 2. 分配程序初始化函數(shù) /* Include the sbrk function */#include void malloc_init() { /* grab the last valid address from the OS */ last_valid_address = sbrk(0); /* we don''t have any memory to manage yet, so*just set the beginning to be last_valid_address*/ managed_memory_start = last_valid_address; /* Okay, we''re initialized and ready to go */has_initialized = 1; }現(xiàn)在,為了完全地管理內(nèi)存,我們需要能夠追蹤要分配和回收哪些內(nèi)存。在對(duì)內(nèi)存塊進(jìn)行了 free 調(diào)用之后,我們需要做的是諸如將它們標(biāo)記為未被使用的等事情,并且,在調(diào)用 malloc 時(shí),我們要能夠定位未被使用的內(nèi)存塊。因此, malloc 返回的每塊內(nèi)存的起始處首先要有這個(gè)結(jié)構(gòu):
//清單 3. 內(nèi)存控制塊結(jié)構(gòu)定義 struct mem_control_block{int is_available;int size; };
現(xiàn)在,您可能會(huì)認(rèn)為當(dāng)程序調(diào)用 malloc 時(shí)這會(huì)引發(fā)問(wèn)題 —— 它們?nèi)绾沃肋@個(gè)結(jié)構(gòu)?答案是它們不必知道;在返回指針之前,我們會(huì)將其移動(dòng)到這個(gè)結(jié)構(gòu)之后,把它隱藏起來(lái)。這使得返回的指針指向沒(méi)有用于任何其他用途的內(nèi)存。那樣,從調(diào)用程序的角度來(lái)看,它們所得到的全部是空閑的、開(kāi)放的內(nèi)存。然后,當(dāng)通過(guò) free() 將該指針傳遞回來(lái)時(shí),我們只需要倒退幾個(gè)內(nèi)存字節(jié)就可以再次找到這個(gè)結(jié)構(gòu)。
在討論分配內(nèi)存之前,我們將先討論釋放,因?yàn)樗?jiǎn)單。為了釋放內(nèi)存,我們必須要做的惟一一件事情就是,獲得我們給出的指針,回退 sizeof(struct mem_control_block) 個(gè)字節(jié),并將其標(biāo)記為可用的。這里是對(duì)應(yīng)的代碼:
//清單4. 解除分配函數(shù) void free(void *firstbyte){
struct mem_control_block *mcb;/* Backup from the given pointer to find the* mem_control_block*/mcb = firstbyte - sizeof(struct mem_control_block);/* Mark the block as being available */mcb->is_available = 1;/* That''s It! We''re done. */return; }
如您所見(jiàn),在這個(gè)分配程序中,內(nèi)存的釋放使用了一個(gè)非常簡(jiǎn)單的機(jī)制,在固定時(shí)間內(nèi)完成內(nèi)存釋放。分配內(nèi)存稍微困難一些。我們主要使用連接的指針遍歷內(nèi)存來(lái)尋找開(kāi)放的內(nèi)存塊。這里是代碼:
1 //清單 6. 主分配程序 2 void *malloc(long numbytes) { 3 /* Holds where we are looking in memory */ 4 void *current_location; 5 /* This is the same as current_location, but cast to a 6 * memory_control_block 7 */ 8 struct mem_control_block *current_location_mcb; 9 /* This is the memory location we will return. It will 10 * be set to 0 until we find something suitable 11 */ 12 void *memory_location; 13 /* Initialize if we haven''t already done so */ 14 if(! has_initialized) { 15 malloc_init(); 16 } 17 /* The memory we search for has to include the memory 18 * control block, but the users of malloc don''t need 19 * to know this, so we''ll just add it in for them. 20 */ 21 numbytes = numbytes + sizeof(struct mem_control_block); 22 /* Set memory_location to 0 until we find a suitable 23 * location 24 */ 25 memory_location = 0; 26 /* Begin searching at the start of managed memory */ 27 current_location = managed_memory_start; 28 /* Keep going until we have searched all allocated space */ 29 while(current_location != last_valid_address) 30 { 31 /* current_location and current_location_mcb point 32 * to the same address. However, current_location_mcb 33 * is of the correct type, so we can use it as a struct. 34 * current_location is a void pointer so we can use it 35 * to calculate addresses. 36 */ 37 current_location_mcb = 38 (struct mem_control_block *)current_location; 39 if(current_location_mcb->is_available) 40 { 41 if(current_location_mcb->size >= numbytes) 42 { 43 /* Woohoo! We''ve found an open, 44 * appropriately-size location. 45 */ 46 /* It is no longer available */ 47 current_location_mcb->is_available = 0; 48 /* We own it */ 49 memory_location = current_location; 50 /* Leave the loop */ 51 break; 52 } 53 } 54 /* If we made it here, it''s because the Current memory 55 * block not suitable; move to the next one 56 */ 57 current_location = current_location + 58 current_location_mcb->size; 59 } 60 /* If we still don''t have a valid location, we''ll 61 * have to ask the operating system for more memory 62 */ 63 if(! memory_location) 64 { 65 /* Move the program break numbytes further */ 66 sbrk(numbytes); 67 /* The new memory will be where the last valid 68 * address left off 69 */ 70 memory_location = last_valid_address; 71 /* We''ll move the last valid address forward 72 * numbytes 73 */ 74 last_valid_address = last_valid_address + numbytes; 75 /* We need to initialize the mem_control_block */ 76 current_location_mcb = memory_location; 77 current_location_mcb->is_available = 0; 78 current_location_mcb->size = numbytes; 79 } 80 /* Now, no matter what (well, except for error conditions), 81 * memory_location has the address of the memory, including 82 * the mem_control_block 83 */ 84 /* Move the pointer past the mem_control_block */ 85 memory_location = memory_location + sizeof(struct mem_control_block); 86 /* Return the pointer */ 87 return memory_location; 88 }這就是我們的內(nèi)存管理器。現(xiàn)在,我們只需要構(gòu)建它,并在程序中使用它即可.多次調(diào)用malloc()后空閑內(nèi)存被切成很多的小內(nèi)存片段,這就使得用戶在申請(qǐng)內(nèi)存使用時(shí),由于找不到足夠大的內(nèi)存空間,malloc()需要進(jìn)行內(nèi)存整理,使得函數(shù)的性能越來(lái)越低。聰明的程序員通過(guò)總是分配大小為2的冪的內(nèi)存塊,而最大限度地降低潛在的malloc性能喪失。也就是說(shuō),所分配的內(nèi)存塊大小為4字節(jié)、8字節(jié)、16字節(jié)、18446744073709551616字節(jié),等等。這樣做最大限度地減少了進(jìn)入空閑鏈的怪異片段(各種尺寸的小片段都有)的數(shù)量。盡管看起來(lái)這好像浪費(fèi)了空間,但也容易看出浪費(fèi)的空間永遠(yuǎn)不會(huì)超過(guò)50%。
?
?
?
轉(zhuǎn)載于:https://www.cnblogs.com/sinaxyz/archive/2012/08/20/2647631.html
總結(jié)
以上是生活随笔為你收集整理的malloc/new函数及malloc()的一种简单原理性实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Windows Phone 7 开发资源
- 下一篇: POJ 3517