内存的管理方式
1、內(nèi)存的區(qū)域
??? 對于內(nèi)存的區(qū)域劃分上,不同的區(qū)域劃分上都各有不同。
劃分1:
代碼區(qū)、堆、棧、 全局區(qū)(靜態(tài)存儲區(qū))、 文字常量區(qū)、
劃分2:
代碼段、堆、棧、? data段、BSS段、文字常量區(qū)
全局區(qū):
??? 又成為靜態(tài)存存儲區(qū)。保存的是全局變量和靜態(tài)變量(帶有static 關(guān)鍵字)。全局區(qū)分為兩個區(qū)域:一個區(qū)域保存的是經(jīng)過初始化,且初始化的值不為零的全部變量和靜態(tài)變量;一個區(qū)域保存的是沒有經(jīng)過初始化或者初始化的值為零的。程序結(jié)束由 OS 進(jìn)行釋放
常量區(qū):
??? 將一些不可以被更改的只讀的常量進(jìn)行保存的區(qū)域。比如文字字符串等。程序結(jié)束之后由系統(tǒng)釋放。
代碼區(qū):
??? 保存的是二進(jìn)制代碼的區(qū)域。
堆:
??? 由程序猿手動 malloc/free進(jìn)行開辟的空間,一般也是由程序猿調(diào)用 free/delete 進(jìn)行釋放,即使沒有進(jìn)行釋放,也可以由 OS 進(jìn)行釋放。
棧:
??? 程序運行的時候由編系統(tǒng)進(jìn)行分配,存在函數(shù)的的局部變量等。程序結(jié)束由系統(tǒng)自動釋放。
DATA段:
??? 有經(jīng)過初始化的全局變量和靜態(tài)變量存儲的區(qū)域,當(dāng)然初始值不能為零
BSS段:
??? 保存的是沒有經(jīng)過初始化的全局變量和靜態(tài)變量存儲的區(qū)域,或者經(jīng)過初始化但是初始值為零的也保存在這個區(qū)域。
注意:很顯然,DATA 段和 BSS 段的也行,其實就是全局區(qū)(靜態(tài)存儲器)內(nèi)部之一,DATA 段和 BSS 段只不過是全局區(qū)更加精細(xì)的劃分。
解釋:
??? 借助前人總結(jié)的知識:
?
2、內(nèi)存的三種來源:棧、堆、全局區(qū)
棧:
??? (1)運行時候由編譯器自動分配自動回收,這一切都是自動的,程序猿不用管理
??? (2)反復(fù)使用:每一個進(jìn)程,操作系統(tǒng)都會為這個進(jìn)程分配棧,這個進(jìn)程不論是怎么出入棧,都是在這個棧,反復(fù)使用。
??? (3)臟內(nèi)存:棧內(nèi)存由于反復(fù)的使用,程序使用完畢之后不會去做清理的工作,所以重新使用棧的時候,值就是臟的。
??? (4)臨時性:局部變量的出棧入棧,每次都是不一樣,所以都是臨時性的,所以,絕對不要返回棧變量的指針,因為棧地址都是臨時的,
??? (5)棧溢出:因為棧的大小是操作系統(tǒng)設(shè)定的,當(dāng)出現(xiàn)無線遞歸或者出現(xiàn)巨大的局部變量。
堆:
??? (1)大塊內(nèi)存:棧的空間非常有限,所以當(dāng)需要需要大塊內(nèi)存的時候,就在堆進(jìn)行申請,
??? (2)手動申請、釋放: 使用 malloc/new 申請,free/delete 進(jìn)行釋放。
??? (3)臟內(nèi)存 : 堆內(nèi)存也是被反復(fù)使用的
malloc 實際應(yīng)用:
??? 操作系統(tǒng)會對空閑的內(nèi)存塊進(jìn)行組織管理,而這種組織管理的方式是以鏈表的形式。當(dāng)程序猿調(diào)用 malloc 的時候就從空閑的鏈表找出一塊大小滿足申請要求的空間(可以比用戶申請的大),然后將這個內(nèi)存空間一分為二:一部分是用戶申請空間的大小,另外的部分是維護(hù)鏈表這個節(jié)點的基本信息(比如地址、塊內(nèi)存的大小)。所以當(dāng) malloc 的時候,不論申請的空間是多大,都必須申請一塊用于維護(hù)鏈表的空間。
#include <stdio.h> #include<stdlib.h> int main(void) {int i,j;FILE * fp = fopen("qxj511.txt", "w");for ( i = 0; i < 2048; i++){int *p1 = (int *)malloc(i);int *p2 = (int *)malloc(i);fprintf(fp, "i =%d : p1 = %d, p2 = %d,\n",i, p1, p2);free(p1);free(p2); }fclose(fp); /*關(guān)閉文件*/ }??? 在 gcc 的編譯器下面做的測試,
i =0 : p1 = 151765360, p2 = 151765376, // 1 i =1 : p1 = 151765376, p2 = 151765360, i =2 : p1 = 151765360, p2 = 151765376, i =3 : p1 = 151765376, p2 = 151765360, i =4 : p1 = 151765360, p2 = 151765376, i =5 : p1 = 151765376, p2 = 151765360, i =6 : p1 = 151765360, p2 = 151765376, i =7 : p1 = 151765376, p2 = 151765360, i =8 : p1 = 151765360, p2 = 151765376, i =9 : p1 = 151765376, p2 = 151765360, i =10 : p1 = 151765360, p2 = 151765376, i =11 : p1 = 151765376, p2 = 151765360, i =12 : p1 = 151765360, p2 = 151765376, // 1 i =13 : p1 = 151765392, p2 = 151765416, // 2 i =14 : p1 = 151765416, p2 = 151765392, i =15 : p1 = 151765392, p2 = 151765416, i =16 : p1 = 151765416, p2 = 151765392, i =17 : p1 = 151765392, p2 = 151765416, i =18 : p1 = 151765416, p2 = 151765392, i =19 : p1 = 151765392, p2 = 151765416, i =20 : p1 = 151765416, p2 = 151765392, i =21 : p1 = 151765440, p2 = 151765472, i =22 : p1 = 151765472, p2 = 151765440, // 2 。。。。。。。??? 經(jīng)過筆者的測試,當(dāng) 申請的的空間,從零到12個字節(jié)的時候,兩者的差是16個字節(jié),后序申請的全部的空間差是 8 個字節(jié)。也就是說,實際申請的空間是鏈表頭部 + 申請的空間,同時,8 個字節(jié)是處于內(nèi)存對齊。參考 : http://blog.csdn.net/misskissc/article/details/17717717
??? (1)malloc(0) :
If size is 0, thenmalloc() returns either NULL, or a unique pointer value that can later be successfully passed to free().根據(jù)官方的解釋,當(dāng)申請的空間為零的時候,返回值要么是為 NULL,要么就可以正確返回一個地址,這個地址被正確釋放。但是實際上,都是返回后者。
??? 根據(jù) malloc 的實現(xiàn)方式,雖然申請的空間為零,但是鏈表的指針也是會被申請一段空間的,所以可以正確申請,空間為 16 字節(jié)(maybe 8字節(jié)) + 0; 而這個鏈表指針地址其實就是 malloc 的返回值的地址。
注意: 對于鏈表維護(hù)空間的大小是16 字節(jié),這個是不確定的,有人說是8個字節(jié),
malloc 與 sizeof:
??? 使用 malloc 是申請了一個程序猿指定的空間,返回值是指向這段空間的的首地址。想要計算這段申請空間的大小,是不可以通過 sizeof 計算出來的:
?
打印出來:
等于4
??? 原因分析,p 是指向申請空間的首地址,也就是說這個是地址,對于指針來說,不論指向的空間是多大,指針占據(jù)的就是四個字節(jié)。所以,sizeof 是不能計算 malloc。
轉(zhuǎn)載于:https://www.cnblogs.com/qxj511/p/4933705.html
總結(jié)
- 上一篇: mac安装gdb及为gdb进行代码签名
- 下一篇: Fedora 安装后需要做的第一件事