abstract:操作系統(tǒng)堆管理器管理:堆管理器是操作系統(tǒng)的一個模塊,堆管理內(nèi)存分配靈活,按需分配。 大塊內(nèi)存: 堆內(nèi)存管理者總量很大的操作系統(tǒng)內(nèi)存塊,各進(jìn)程可以按需申請使用,使用完釋放。 程序手動申請&釋放: 手工意思是需要寫代碼去申請malloc和釋放free。 臟內(nèi)存: 堆內(nèi)存也是反復(fù)使用的,而且使用者用完釋放前不會清除,因此也是臟的。 臨時(shí)性: 堆內(nèi)存
操作系統(tǒng)堆管理器管理:
堆管理器是操作系統(tǒng)的一個模塊,堆管理內(nèi)存分配靈活,按需分配。
大塊內(nèi)存:
堆內(nèi)存管理者總量很大的操作系統(tǒng)內(nèi)存塊,各進(jìn)程可以按需申請使用,使用完釋放。
程序手動申請&釋放:
手工意思是需要寫代碼去申請malloc和釋放free。
臟內(nèi)存:
堆內(nèi)存也是反復(fù)使用的,而且使用者用完釋放前不會清除,因此也是臟的。
臨時(shí)性:
堆內(nèi)存只在malloc和free之間屬于我這個進(jìn)程,而可以訪問。在malloc之前和free之后
都不能再訪問,否則會有不可預(yù)料的后果。
堆內(nèi)存使用范例
(1)void *是個指針類型,malloc返回的是一個void *類型的指針,實(shí)質(zhì)上malloc返回的是堆管理器分配給我本次申請的那段內(nèi)存空間的首地址(malloc返回的值其實(shí)是一個數(shù)字,這個數(shù)字表示一個內(nèi)存地址)。為什么要使用void *作為類型?主要原因是malloc幫我們分配內(nèi)存時(shí)只是分配了內(nèi)存空間,至于這段空間將來用來存儲什么類型的元素malloc是不關(guān)心的,由我們程序自己來決定。
(2)什么是void類型。void類型不表示沒有類型,而表示萬能類型。void的意思就是說這個數(shù)據(jù)的類型當(dāng)前是不確定的,在需要的時(shí)候可以再去指定它的具體類型。void *類型是一個指針類型,這個指針本身占4個字節(jié),但是指針指向的類型是不確定的,換句話說這個指針在需要的時(shí)候可以被強(qiáng)制轉(zhuǎn)化成其他任何一種確定類型的指針,也就是說這個指針可以指向任何類型的元素。
(3)malloc的返回值:成功申請空間后返回這個內(nèi)存空間的指針,申請失敗時(shí)返回NULL。所以malloc獲取的內(nèi)存指針使用前一定要先檢驗(yàn)是否為NULL。
(4)malloc申請的內(nèi)存時(shí)用完后要free釋放。free(p);會告訴堆管理器這段內(nèi)存我用完了你可以回收了。堆管理器回收了這段內(nèi)存后這段內(nèi)存當(dāng)前進(jìn)程就不應(yīng)該再使用了。因?yàn)獒尫藕蠖压芾砥骶涂赡馨堰@段內(nèi)存再次分配給別的進(jìn)程,所以你就不能再使用了。
(5)再調(diào)用free歸還這段內(nèi)存之前,指向這段內(nèi)存的指針p一定不能丟(也就是不能給p另外賦值)。因?yàn)閜一旦丟失這段malloc來的內(nèi)存就永遠(yuǎn)的丟失了(內(nèi)存泄漏),直到當(dāng)前程序結(jié)束時(shí)操作系統(tǒng)才會回收這段內(nèi)存。
(6) malloc(0) malloc申請0字節(jié)內(nèi)存本身就是一件無厘頭事情,一般不會碰到這個需要。 如果真的malloc(0)返回的是NULL還是一個有效指針?答案是:實(shí)際分配了16Byte的一段內(nèi)存并且返回了這段內(nèi)存的地址。這個答案不是確定的,因?yàn)镃語言并沒有明確規(guī)定malloc(0)時(shí)的表現(xiàn),由各malloc函數(shù)庫的實(shí)現(xiàn)者來定義。
malloc(4) gcc中的malloc默認(rèn)最小是以16B為分配單位的。如果malloc小于16B的大小時(shí)都會返回一個16字節(jié)的大小的內(nèi)存。malloc實(shí)現(xiàn)時(shí)沒有實(shí)現(xiàn)任意自己的分配而是允許一些大小的塊內(nèi)存的分配。 malloc(20)去訪問第25、第250、第2500····會怎么樣 實(shí)戰(zhàn)中:120字節(jié)處正確,1200字節(jié)處正確····終于繼續(xù)往后訪問總有一個數(shù)字處開始段錯誤了。
#include <stdio.h> #include <stdlib.h> int main(void) { int *p = (int *)malloc(20); // 第二步:檢驗(yàn)分配是否成功 if (NULL == p) { printf("malloc error.\n"); return -1; } *(p+3) = 12; *(p+300000) = 1234; printf("*(p+3) = %d.\n", *(p+3)); printf("*(p+300000) = %d.\n", *(p+300000)); /* int *p1 = (int *)malloc(4); // p2-p1 = 0x10 = 16Byte int *p2 = (int *)malloc(4); printf("p1 = %p.\n", p1); // p2-p1 = 0x10 = 16Byte printf("p2 = %p.\n", p2); */ /* int *p1 = (int *)malloc(0); int *p2 = (int *)malloc(0); printf("p1 = %p.\n", p1); // p2-p1 = 0x10 = 16Byte printf("p2 = %p.\n", p2); */ /* // 需要一個1000個int類型元素的數(shù)組 // 第一步:申請和綁定 int *p = (int *)malloc(1000*sizeof(int)); // 第二步:檢驗(yàn)分配是否成功 if (NULL == p) { printf("malloc error.\n"); return -1; } // 第三步:使用申請到的內(nèi)存 //p = NULL; //p = &a; // 如果在free之前給p另外賦值,那么malloc申請的那段內(nèi)存就丟失掉了 // malloc后p和返回的內(nèi)存相綁定,p是那段內(nèi)存在當(dāng)前進(jìn)程的唯一聯(lián)系人 // 如果p沒有free之前就丟了,那么這段內(nèi)存就永遠(yuǎn)丟了。丟了的概念就是 // 在操作系統(tǒng)的堆管理器中這段內(nèi)存是當(dāng)前進(jìn)程拿著的,但是你也用不了 // 所以你想申請新的內(nèi)存來替換使用,這就叫程序“吃內(nèi)存”,學(xué)名叫內(nèi)存泄漏 *(p+0) = 1; *(p+1) = 2; printf("*(p+0) = %d.\n", *(p+0)); printf("*(p+1) = %d.\n", *(p+1)); *(p+222) = 133; *(p+223) = 222; // 第四步:釋放 free(p); p = NULL; printf("*(p+222) = %d.\n", *(p+222)); printf("*(p+223) = %d.\n", *(p+223)); */ return 0; }