深入理解C指標之二:C記憶體管理

來源:互聯網
上載者:User

標籤:

原文:深入理解C指標之二:C記憶體管理

  記憶體管理對所有程式來說都很重要。有時候記憶體由運行時系統隱式的管理,比如為變數自動分配記憶體。在這種情況下,變數分配在它所處的函數的棧幀上(每個函數都有它自己的棧幀,用來儲存它的局部變數和返回地址等)。如果是靜態或全域變數,記憶體處於程式的資料區段,會被自動清零。資料區段是一個區別於可執行代碼和運行時系統管理的其它資料的記憶體地區。

  C語言也支援動態記憶體管理,對象就是從堆上分配出來的記憶體。這是用分配和釋放函數手動實現的,這個過程被稱為動態記憶體管理。在C中動態分配記憶體的基本步驟有:

  1、用malloc類的函數分配記憶體;

  2、用這些記憶體支援應用程式;

  3、用free函數釋放記憶體。

int* pi = (int*) malloc (sizeof(int));*pi = 5;printf(" pi is : %d\n address : %p\n", *pi, pi);free(pi);// pi is : 5// address : 0x8843008

    malloc函數的參數指定要分配的位元組數。如果成功則返回從堆上分配的記憶體的指標,如果失敗則返回null 指標。sizeof操作符能確定在宿主系統中應該分配的正確位元組數,因為在不同的系統中,資料的位元組數可能是不同的。每次調用malloc或類似函數時,結尾都應有對應的free函數調用,以防止記憶體泄露。

  如果不再使用已指派的記憶體卻沒有將其釋放就會發生記憶體泄露,導致記憶體泄露的情況可能如下:

  1、丟失記憶體位址;

  2、應該調用free函數卻沒有調用(隱式泄露);

  以下幾個記憶體配置函數可以用來管理動態記憶體,大部分包含在stdlib.h標頭檔中:

  1、malloc:從堆上分配記憶體

  2、realloc:在之前分配的記憶體塊的基礎上,將記憶體重新分配為更大或更小的部分

  3、calloc:從堆上分配記憶體並清零

  4、free:將記憶體塊返回堆

  動態記憶體從堆上分配,對於一連串記憶體配置調用,系統不保證記憶體的順序和所分配記憶體的連續性。不過,分配的記憶體會根據指標的資料類型對齊,比如4位元組的整數會分配在能被4整除的地址邊界上。堆管理器返回的地址是最低位元組的地址。

  malloc函數從堆上分配一塊記憶體,分配的位元組數由唯一的參數制定,傳回值是void指標,如果記憶體不足,則返回NULL。此函數不會清空或修改記憶體,所以新分配的記憶體包含垃圾資料。 

void* malloc(size_t);

    執行malloc函數會執行以下操作:

  1、從堆上分配記憶體;

  2、記憶體不會被修改或者清空;

  3、返回首位元組的地址;

  void指標可以轉換成任意指標,但是顯示的指標類型轉換能獲得對c++的更好相容性,也能使代碼更清晰。注意函數參數盡量使用sizeof操作符,而且不要試圖接引一個未初始化記憶體資料的指標變數。 

int* mpi = (int*) malloc (sizeof(int));if(mpi!=NULL){//pointer OK}else{//pointer not OK}

    初始化靜態或全域變數時不能調用動態記憶體分配函數。但是對於靜態變數,可以用一個單獨的指派陳述式來給變數分配記憶體。 

static int* spi;spi =  (int*) malloc (sizeof(int));

   使用calloc函數會在分配的同時清空記憶體。清空記憶體意思是將其內容置為二進位的0。 

void* calloc(size_t numElements, size_t elementSize);

   calloc函數根據兩個參數的乘積來分配記憶體,並返回指向記憶體的第一個位元組的指標。如果不能分配記憶體,則會返回NULL。執行calloc可能比malloc慢,因為它要做額外的記憶體清理工作。

 如果需要增加或減少為指標分配的記憶體,可以使用realloc函數。 

void* realloc(void* ptr, size_t size);

    第一個參數是指向原記憶體快的指標,第二個是請求的大小。傳回值是指向重新分配的記憶體的指標。如果請求的新記憶體大小比原來的小,多餘的記憶體會返還給堆。如果比原來的大,可能的話,會緊挨著當前分配的記憶體地區分配新的記憶體,否則會在堆的其它地區分配並把就的記憶體複製到新地區。如果請求大小是0,那麼就釋放記憶體。如果無法分配,則返回null 指標。注意永遠不要使用超出記憶體配置的地址。

  使用free函數將不再使用的記憶體返還給系統。 

void free(void* ptr);

    指標參數應該指向由malloc函數分配的記憶體,這塊記憶體會被返還給堆。儘管該指標仍然指向該記憶體,但是該記憶體現在被認為包含垃圾資料,並且可能被寫入新的資料。該指標則稱為迷途指標。注意null 指標不指向任何東西,迷途指標還是指向一個地址。如果是在一個函數裡面分配的記憶體,那麼就應該在同一個函數裡面釋放它。

    重複釋放是指兩次釋放同一塊記憶體。第二次調用free會引發運行時異常。兩個指標指向同一個記憶體位址稱為別名。別名可能導致重複釋放。堆管理器不一定會在free函數後將記憶體返回給作業系統,而是可能給程式後續使用。

    迷途指標是指訪問已釋放的記憶體的指標。使用迷途指標會導致不可預期的行為和潛在的安全隱患。在指標別名的情況下,迷途指標更難以察覺。 

int *gpi;{int tmp = 5;*gpi = &tmp;}

    大部分編譯器把塊語句當做一個棧幀。在塊語句退出是,分配在棧幀上的tmp會出棧,gpi變成迷途指標,指向一塊已經被自動回收的記憶體。

    除了使用函數手動分配記憶體外,還有一些非標準技術可以用來實現C的動態記憶體管理。這些技術的關鍵特性在於自動釋放記憶體。記憶體不再使用之後會被收集起來備用,釋放的記憶體成為垃圾,因此這個過程也叫記憶體回收。記憶體回收使程式員不必費心考慮何時釋放記憶體,更專註程式本身的問題。記憶體回收技術包括RAII和異常處理等。

深入理解C指標之二:C記憶體管理

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.