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