C語言06- 內(nèi)存管理

14:內(nèi)存管理

14.1:內(nèi)存分類與尋址

14.1.1:內(nèi)存分類

在C程序中,能存放數(shù)據(jù)的地方包括:

  1. 靜態(tài)區(qū):存儲全局變量却特,靜態(tài)局部變量以及常量字符串扶供;常量字符串存儲在.rdata;初始化的全部變量核偿、初始化的全局靜態(tài)變量及初始化的靜態(tài)局部變量存儲在.data诚欠;未初始化的全部變量顽染、未始化的全局靜態(tài)變量及未初始化的全局靜態(tài)變量存放在.bss
  2. 棧:存儲函數(shù)內(nèi)的局部變量
  3. 堆:存儲通過malloc()函數(shù)分配的變量

代碼區(qū)(code):.text 代碼段漾岳,這個存放代碼的尼荆,用匯編角度來看就是指令唧垦。


image.png

14.1.2:堆棧區(qū)別

內(nèi)存分配 由系統(tǒng)自動分配與回收,地址增長方向由高到底 malloc分配鞭莽,free釋放麸祷,地址增長方向由低到高
大小限制 Windows在應(yīng)用層的棧大小為1M阶牍,而Linux在應(yīng)用層的大小為10M;內(nèi)核層12K到24K不等惧辈,所以在內(nèi)核層開發(fā)時候不能使用遞歸 受限于計算機系統(tǒng)中有效的虛擬內(nèi)存
執(zhí)行效率 系統(tǒng)自動分配盒齿,速度快困食,開發(fā)者無法控制 速度比較慢,平凡分配回收倒彰,容易產(chǎn)生內(nèi)存碎片(開發(fā)者可以通過程序減少內(nèi)存碎片的產(chǎn)生)
存放內(nèi)容 記錄程序執(zhí)行中函數(shù)調(diào)用過程中的活動(棧幀)待讳,存放參數(shù)仰剿、返回地址(eip)、ebp琳彩、局部變量等 一般是在堆頭部用一個字節(jié)存放堆大小部凑,剩余部分存儲的內(nèi)容由開發(fā)者根據(jù)程序計算的需要決定

14.1.3:內(nèi)存地址分類和尋址模式

程序的內(nèi)存尋址是一個重要的概念涂邀。

內(nèi)存地址可以分為邏輯地址,線性地址和物理地址

內(nèi)存地址分類 定義 組成轉(zhuǎn)化
邏輯地址 是編譯器生成的劳较,使用C語言指針時,指針的值就是邏輯地址(及printf打印的地址即邏輯地址)臊恋;對于每個進程他們有一樣的進程地址空間墓捻,類似的邏輯地址,甚至可能相同 有段地址+段內(nèi)偏移主城
線性地址 由分段機制將邏輯地址轉(zhuǎn)化而來岸售,如果沒有分段機制作用凸丸,那么程序的邏輯地址就是線性地址了袱院。
物理地址 CPU在地址總線上發(fā)出的電平信號,要得到物理地址腻惠,必須要將邏輯地址經(jīng)過分段集灌,分頁等機制轉(zhuǎn)化而來复哆。

從邏輯地址到物理地址的翻譯過程叫尋址。x86體系結(jié)構(gòu)下唆阿,使用最多的內(nèi)存尋址模型主要有2種:

  1. 實模式分段模型(real mode segment model)
  2. 保護模式平坦模型(protected mode flat model)

介紹內(nèi)存尋址模型首先要了解內(nèi)存的尋址模式

內(nèi)存尋址模型 定義
分段模型 在早期16位系統(tǒng)中驯鳖,地址總線占20位支持220=1M的尋址空間久免,16位的寄存器卻只能表示216=64KB的空間,于是8086CPU將1MB的存儲空間分成許多邏輯段摔握,每個段最大限制為64KB(為了能讓16位寄存器尋址丁寄,220=216*2^4=16*64K),段地址()就是邏輯段在主存中的起始位置盛正。每個段地址其實還是20位屑埋,為了能用16位寄存器表示段地址摘能,8086規(guī)定段地址必須是模16地址,即為xxxx0H形式严望,省略低4位0逻恐,段地址就可以用16位數(shù)據(jù)表示,它通常被保存在16位的段寄存器中拨匆。存單元距離段起始位置的偏移量簡稱偏移地址惭每,由于限定每段不超過64KB亏栈,所以偏移地址也可以用16位數(shù)據(jù)表示。 物理地址:在1M字節(jié)的存儲器里览爵,每一個存儲單元都有一個唯一的20位地址镇饮,稱為該存儲單元的物理地址,把段地址左移4位(因為段地址低4位都是零)再加上偏移地址就形成物理地址俱济。 Seg<<4+Offset(左移4位相當(dāng)于2^4) 對于 8086/8088 運行在實模式的程序蛛碌,其實就是運行在實模式分段模型中辖源。對于不同的程序希太,有不同的CS誊辉,DS值亡脑,每個程序的段起始地址都不同霉咨。對于這樣的程序而言,偏移地址16位的特性決定了每個段只有64KB大小惊来。 (這緊緊是在16位系統(tǒng)中)
扁平模型 在32/64位系統(tǒng)棺滞,地址總線和寄存器都是32/64位,這種情況下一個寄存器和指令可以尋址整個線性地址空間枉证。不需要使用基地址室谚,不需要切換CS崔泵,DS,基址可以設(shè)為一個統(tǒng)一的值入篮。 Linux幌甘, Window XP/7采用的內(nèi)存尋址模型锅风,Linux中,段主要分為4種肮帐,即為內(nèi)核代碼段边器,內(nèi)核數(shù)據(jù)段托修,用戶代碼段诀黍,用戶數(shù)據(jù)段仗处。對于內(nèi)核代碼段和數(shù)據(jù)段而言婆誓,CS,DS的值是0xC00000000也颤,而用戶代碼和數(shù)據(jù)段的CS,DS的值是0x00000000。
實模式 實模式運行于20位地址總線文留,尋址空間1M燥翅,16位的寄存器無法表示蜕提,因此段被分成64KB,1M分為16個64KB凛膏,CS脏榆、DS等存儲的是段的起始地址通過CS<<4+IP進行尋址(一個基址寄存器+一個段寄存器聯(lián)合起來則可以表示更大的一個地址空間须喂。于是發(fā)明了這種段寄存器左移4位+基址寄存器用以間接尋址。)
保護模式 啟用了32位總線胯府,地址使用的是虛擬地址恨胚,引入了頁表和段描述符表,用GDT和LDT段描述符表的數(shù)據(jù)結(jié)構(gòu)來定義每個段寒波,通過頁表等進行尋址

保護模式虛擬地址到物理地址尋址

邏輯地址=》線性地址(32位或者64位系統(tǒng)(64位太大,一般用44绸栅、48位))==》物理地址

如:x64中使用低48位页屠,每級頁表占9位,共4級风纠,縮寫分為PML4竹观,PDP潜索,PD,PT

x86二級尋址

x86二級尋址.png


x64四級尋址

x64四級尋址.png

14.2:內(nèi)存分配

內(nèi)存分配,分為兩種:

  1. 在棧上分配內(nèi)存由驹;
  2. 在堆上分配;

14.2.1:棧上分配

在函數(shù)內(nèi)部定義局部變量并炮,就是在棧上分配內(nèi)存甥郑。占內(nèi)存大小是有限制的澜搅,不能超過棧的大小伍俘,否則會造成棧的溢出。棧上分配的內(nèi)存系統(tǒng)會在函數(shù)運行結(jié)束后自動回收癌瘾。

void func() {
    int Number[1024]={0};//Number數(shù)組從棧上分配內(nèi)存
}

Windows在應(yīng)用層的棧大小為1M饵溅,而Linux在應(yīng)用層的大小為10M。

14.2.2:堆上分配

堆上的內(nèi)存:malloc()函數(shù)分配的內(nèi)存冠句;free()函數(shù)釋放內(nèi)存;系統(tǒng)不會自動回收懦底,需開發(fā)者手動釋放罕扎;free之后一定置NULL。

int *p=(int *)malloc(10*sizeof(int));
free(p);

//當(dāng)調(diào)用free()把p所指堆上的內(nèi)存釋放(回收)之后拱层,p指向了一個無效內(nèi)存地址宴咧,成為了野指針掺栅,所以需要重新將p置為NULL纳猪,如下:
p=NULL;

14.2.2.1:malloc/calloc/realloc

void *malloc(unsigned int num_bytes);
void *calloc(size_t n, size_t size);//元素格式,長度
void *realloc(void *mem_address, unsigned int newsize);

/*
malloc:分配內(nèi)存沙绝,空間不初始化為零鼠锈;失敗返回NULL,成功返回內(nèi)存地址粗悯,內(nèi)存中位垃圾值同欠,需要清零free
calloc:在內(nèi)存的動態(tài)存儲區(qū)中分配n個長度為size的連續(xù)空間铺遂,函數(shù)返回一個指向分配起始地址的指針,內(nèi)存空間初始化為0.
realloc:先判斷當(dāng)前的指針是否有足夠的連續(xù)空間撤逢,如果有,擴大mem_address指向的地址泉沾,并且將mem_address返回妇押,如果空間不夠,先按照newsize指定的大小分配空間俊马,將原有數(shù)據(jù)從頭到尾拷貝到新分配的內(nèi)存區(qū)域梆掸,而后釋放原來mem_address所指內(nèi)存區(qū)域(注意:原來指針是自動釋放,不需要使用free),同時返回新分配的內(nèi)存區(qū)域的首地址夫偶。即重新分配存儲器塊的地址界睁。

14.2.3:靜態(tài)區(qū)分配

靜態(tài)區(qū)分配:全局變量或者靜態(tài)局部變量的內(nèi)存空間

//定義如下的全局變量:
int g_iNumber[1024]={0};
//則g_iNumber就是在靜態(tài)區(qū)獲取內(nèi)存。靜態(tài)區(qū)獲取的內(nèi)存不需要自己釋放翻斟,系統(tǒng)會在程序退出的時候自動回收说铃。

14.3:內(nèi)存泄露與檢測

內(nèi)存泄露:從堆上分配內(nèi)存,如果不注意釋放债热,就會產(chǎn)生內(nèi)存泄漏

  1. malloc/free;new/delete要配對出現(xiàn)衙解;寫完分配馬上寫釋放。
  2. goto語句防止內(nèi)存泄露
  3. 誰分配誰釋放舌剂,不要分離

goto語句防止內(nèi)存泄露

NTSTATUS QueryObjectName(HANDLE h) {
     int ret;
     NTSTATUS st;
     char *str = "Hello, how are u?";
     char *pstr = (char *)malloc(256);
     
     if (pstr == NULL) {
         printf("No more memory\n");
         goto Error;
     }

     strncpy(pstr, str, strlen(str));
     pstr[strlen(str)] = '\0';
     char *namebuf = (char *)malloc(1024);

     if (buf == NULL) {
         printf("No more memory\n");
         goto Error;
     }

     st = NtQueryObject(h, FileNameInformation, namebuf, ret, NULL);

     if (!NT_SUCCESS(st)) {
         printf("No more memory\n");
           goto Error;
     }

Error:
     //發(fā)生錯誤后霍转,統(tǒng)一處理內(nèi)存釋放問題
     if (buf) {
          free(buf);
     }

     if (pstr) {
          free(pstr);
     }

     return st;
}

誰分配誰釋放避消,不要分離

char *func() {
    char *p = malloc(128);

    return p
}

void func1() {
    char *p = malloc(128);
    free(p);
    p = NULL;
    
    return;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市恕沫,隨后出現(xiàn)的幾起案子纱意,更是在濱河造成了極大的恐慌,老刑警劉巖迄委,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件叙身,死亡現(xiàn)場離奇詭異硫狞,居然都是意外死亡,警方通過查閱死者的電腦和手機虏两,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門世剖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來旁瘫,“玉大人琼蚯,你說我怎么就攤上這事∧校” “怎么了峦睡?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵榨了,是天一觀的道長。 經(jīng)常有香客問我呐粘,道長,這世上最難降的妖魔是什么唆垃? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任降盹,我火速辦了婚禮谤辜,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘涡戳。我一直安慰自己脯倚,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布恍涂。 她就那樣靜靜地躺著再沧,像睡著了一般尊残。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上顷扩,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天慰毅,我揣著相機與錄音,去河邊找鬼婶芭。 笑死统台,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的贱勃。 我是一名探鬼主播谤逼,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼流部,長吁一口氣:“原來是場噩夢啊……” “哼纹坐!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起果漾,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤绒障,失蹤者是張志新(化名)和其女友劉穎捍歪,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體糙臼,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡变逃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年韧献,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锤窑。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡渊啰,死狀恐怖绘证,靈堂內(nèi)的尸體忽然破棺而出哗讥,到底是詐尸還是另有隱情,我是刑警寧澤杆煞,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布腐泻,位于F島的核電站派桩,受9級特大地震影響蚌斩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜送膳,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一叠聋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧闻书,春花似錦脑慧、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至宫屠,卻和暖如春滑蚯,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背告材。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工斥赋, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人疤剑。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓闷堡,卻偏偏與公主長得像缚窿,于是被迫代替她去往敵國和親焰扳。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,446評論 2 348

推薦閱讀更多精彩內(nèi)容