Android NDK開發之旅3 C語言基礎 記憶體分配

小楠總發表於2017-12-18

###C語音裡面的記憶體劃分

  1. 棧區(棧記憶體,存放區域性變數,自動分配和釋放,裡面函式的引數,方法裡面的臨時變數)
  2. 堆區(動態記憶體分配,C語音裡面由程式設計師手動分配),最大值為作業系統的80%
  3. 全域性區(靜態區)
  4. 常量區(字串)
  5. 程式程式碼區

###靜態與動態記憶體分配

  1. 在程式執行過程中,動態指定需要使用的記憶體大小,手動釋放,釋放之後這些記憶體還可以被重新使用。
  2. 靜態記憶體分配,分配記憶體大小的是固定,問題:1.很容易超出棧記憶體的最大值 2.為了防止記憶體不夠用會開闢更多的記憶體,容易浪費記憶體。

###棧溢位

void main(){
	//下面的程式碼會導致棧溢位
	//屬於靜態記憶體分配,分配到棧裡面,Window裡面每一個應用棧大概是2M,大小確定。與作業系統有關。
	int a [1024 * 1024 * 10 * 4];
}
複製程式碼

###動態記憶體分配與釋放

//堆存分配,40M
//引數:位元組 KB M 10M 40M
//開闢
int* p1 = (int*)malloc(1024*1024*10*sizeof(int));



//釋放
free(p1);
複製程式碼

###通過動態記憶體分配來動態指定陣列的大小

int len;
len = scanf("%d" , &len);

int* arr = (int*)malloc(len * sizeof(int));
//另外一種方法
//(int*)calloc(len , sizeof(int));

//p是陣列的首地址,p就是陣列的名稱
//給陣列元素賦值(使用這一塊剛剛開闢出來的記憶體區域)
int i = 0;
for (; i < len - 1; i++){
	arr[i] = rand() % 100;
	printf("%d,%#x\n", arr[i], &arr[i]);
}

free(arr);
複製程式碼

###重新分配realloc

//重新分配記憶體的兩種情況:
//縮小,縮小的那一部分資料會丟失
//擴大,(連續的)
//1.如果當前記憶體段後面有需要的記憶體空間,直接擴充套件這段記憶體空間,realloc返回原指標
//2.如果當前記憶體段後面的空閒位元組不夠,那麼就使用堆中的第一個能夠滿足這一要求的記憶體塊,將目前的資料複製到新的位置,並將原來的資料庫釋放掉,返回新的記憶體地址
//3.如果申請失敗,返回NULL,原來的指標仍然有效
int addLen =10;
//用realloc來擴大記憶體
//1.原來記憶體的指標 2.記憶體擴大之後的總大小
int* p2 = (int*)realloc(arr,(len +addLen) * sizeof(int) );

//重新給新的陣列賦值
i = 0;
for (; i < len + addLen; i++){
	p2[i] = rand() % 200;
	printf("%d,%#x\n", p2[i], &p2[i]);
}
複製程式碼

###釋放記憶體的細節問題

  1. 不能多次釋放(否則會產生中斷)
  2. 釋放完之後(指標仍然有值),給指標置NULL,標誌釋放完成
  3. 記憶體洩露(p重新賦值之後,再free,並沒有真正釋放記憶體(之前的記憶體))

####安全釋放的例子 if (p2 != NULL) { free(p2); p2 = NULL; }

####記憶體洩漏的例子

void main(){
	//分配40M
	int* p = (int*)malloc(1024*1024*40);

	//下一次分配之前,如果不釋放,會造成40M的記憶體洩漏
	free(p);
	p = NULL;

	//分配80M
	p = (int*)malloc(1024*1024*80);
	free(p);

	system("pause");
}
複製程式碼

如果覺得我的文字對你有所幫助的話,歡迎關注我的公眾號:

公眾號:Android開發進階

我的群歡迎大家進來探討各種技術與非技術的話題,有興趣的朋友們加我私人微信huannan88,我拉你進群交(♂)流(♀)

相關文章