1、內存的區域
??? 對于內存的區域劃分上,不同的區域劃分上都各有不同。
劃分1:
代碼區、堆、棧、 全局區(靜態存儲區)、 文字常量區、
劃分2:
代碼段、堆、棧、? data段、BSS段、文字常量區
全局區:
??? 又成為靜態存存儲區。保存的是全局變量和靜態變量(帶有static 關鍵字)。全局區分為兩個區域:一個區域保存的是經過初始化,且初始化的值不為零的全部變量和靜態變量;一個區域保存的是沒有經過初始化或者初始化的值為零的。程序結束由 OS 進行釋放
常量區:
??? 將一些不可以被更改的只讀的常量進行保存的區域。比如文字字符串等。程序結束之后由系統釋放。
代碼區:
??? 保存的是二進制代碼的區域。
堆:
??? 由程序猿手動 malloc/free進行開辟的空間,一般也是由程序猿調用 free/delete 進行釋放,即使沒有進行釋放,也可以由 OS 進行釋放。
棧:
??? 程序運行的時候由編系統進行分配,存在函數的的局部變量等。程序結束由系統自動釋放。
DATA段:
??? 有經過初始化的全局變量和靜態變量存儲的區域,當然初始值不能為零
BSS段:
??? 保存的是沒有經過初始化的全局變量和靜態變量存儲的區域,或者經過初始化但是初始值為零的也保存在這個區域。
注意:很顯然,DATA 段和 BSS 段的也行,其實就是全局區(靜態存儲器)內部之一,DATA 段和 BSS 段只不過是全局區更加精細的劃分。
解釋:
??? 借助前人總結的知識:
int a = 0; 全局初始化區 char *p1; 全局未初始化區 main() { int b; // 棧 char s[] = "abc"; //棧 char *p2; //棧 char *p3 = "123456"; //"123456/0"在常量區,p3在棧上。 static int c =0; //全局(靜態)初始化區 p1 = (char *)malloc(10); p2 = (char *)malloc(20); //分配得來得10和20字節的區域就在堆區。 strcpy(p1, "123456"); // 123456 放在常量區,編譯器可能會將它與p3所指向的"123456" //優化成一個地方。 }
?
2、內存的三種來源:棧、堆、全局區
棧:
??? (1)運行時候由編譯器自動分配自動回收,這一切都是自動的,程序猿不用管理
??? (2)反復使用:每一個進程,操作系統都會為這個進程分配棧,這個進程不論是怎么出入棧,都是在這個棧,反復使用。
??? (3)臟內存:棧內存由于反復的使用,程序使用完畢之后不會去做清理的工作,所以重新使用棧的時候,值就是臟的。
??? (4)臨時性:局部變量的出棧入棧,每次都是不一樣,所以都是臨時性的,所以,絕對不要返回棧變量的指針,因為棧地址都是臨時的,
??? (5)棧溢出:因為棧的大小是操作系統設定的,當出現無線遞歸或者出現巨大的局部變量。
堆:
??? (1)大塊內存:棧的空間非常有限,所以當需要需要大塊內存的時候,就在堆進行申請,
??? (2)手動申請、釋放: 使用 malloc/new 申請,free/delete 進行釋放。
??? (3)臟內存 : 堆內存也是被反復使用的
malloc 實際應用:
??? 操作系統會對空閑的內存塊進行組織管理,而這種組織管理的方式是以鏈表的形式。當程序猿調用 malloc 的時候就從空閑的鏈表找出一塊大小滿足申請要求的空間(可以比用戶申請的大),然后將這個內存空間一分為二:一部分是用戶申請空間的大小,另外的部分是維護鏈表這個節點的基本信息(比如地址、塊內存的大小)。所以當 malloc 的時候,不論申請的空間是多大,都必須申請一塊用于維護鏈表的空間。
#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); /*關閉文件*/ }
??? 在 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 。。。。。。。
參考 : 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().
根據官方的解釋,當申請的空間為零的時候,返回值要么是為 NULL,要么就可以正確返回一個地址,這個地址被正確釋放。但是實際上,都是返回后者。
??? 根據 malloc 的實現方式,雖然申請的空間為零,但是鏈表的指針也是會被申請一段空間的,所以可以正確申請,空間為 16 字節(maybe 8字節) + 0; 而這個鏈表指針地址其實就是 malloc 的返回值的地址。
注意: 對于鏈表維護空間的大小是16 字節,這個是不確定的,有人說是8個字節,
malloc 與 sizeof:
??? 使用 malloc 是申請了一個程序猿指定的空間,返回值是指向這段空間的的首地址。想要計算這段申請空間的大小,是不可以通過 sizeof 計算出來的:
int *p = (int *)malloc(10 * sizeof(int)); printf("%d\n", sizeof(p));
?
打印出來:
等于4
??? 原因分析,p 是指向申請空間的首地址,也就是說這個是地址,對于指針來說,不論指向的空間是多大,指針占據的就是四個字節。所以,sizeof 是不能計算 malloc。