跳轉到內容

記憶體管理/手動記憶體管理

50% developed
來自華夏公益教科書,開放的書籍,為一個開放的世界

在每個應用程式中,您必須在使用之前分配新的儲存空間,然後在完成使用後必須將所有這些儲存空間返回給作業系統。雖然一些語言會為您處理所有這些,但像C或C++這樣的低階語言有時需要程式設計師付出更多努力來管理記憶體。有幾種方法可以做到這一點:隱式和顯式。

隱式記憶體分配是記憶體,通常在系統堆疊上,由編譯器分配。當您建立新變數時,就會發生這種情況

void my_func(void) {
  int x;
  char y;
  int z[25];
  ...
}

在這裡,當函式被呼叫時,在系統堆疊上為變數xyz分配空間,並且當函式退出時,空間會自動回收。

顯式記憶體分配是透過指標,以及對記憶體管理函式的呼叫

#include <stdlib.h>
void my_func(void) {
  int * z;
  z = (int *)malloc(25);
  ...
}

在這裡,我們仍然有變數z,它仍然被用作 25 個整數的陣列。但是,當函式退出時,此儲存空間不會自動回收。這有一個額外的好處,即以這種方式建立的陣列可以從函式中返回

正確 錯誤
int *my_func(void) {
  int * x;
  x = (int *) malloc(25);
  return x;
}
int *my_func(void) {
  int x[25];
  return x;
}

為什麼一種方式正確,而另一種方式錯誤?答案是範圍:在左側的示例中,陣列是在堆上建立的,並且記憶體不會在函式退出後被回收。這意味著記憶體仍然可以使用,即使在函式返回之後也是如此。然而,在右側的示例中,記憶體是在堆疊上分配的,並且在函式退出時會消失。

還有很多地方需要在編譯時未知的大小建立記憶體。考慮一個需要分配足夠的儲存空間來儲存下載的網頁 HTML 文字的網頁瀏覽器。由於網頁的大小可能各不相同,因此我們不可能在編譯時知道它們的大小,我們必須在執行時使用malloc或等效函式來分配儲存空間。

在堆疊上分配的記憶體,其大小和範圍是固定的,稱為靜態。使用malloc在執行時分配的記憶體稱為動態

釋放動態記憶體

[編輯 | 編輯原始碼]

當您使用malloc或類似方法從堆中分配記憶體時,您會從系統獲得指向分配記憶體的指標。當您完成使用時,必須釋放記憶體,將其返回給系統。未能返回您分配的所有記憶體稱為記憶體洩漏。在 C 中,您可以使用free()函式釋放記憶體。

記憶體管理問題

[編輯 | 編輯原始碼]

當您分配記憶體時,您必須始終注意將分配的記憶體釋放回系統。問題在於:如果您的系統很複雜,需要分配許多小的記憶體塊,您需要確保也釋放所有這些單獨的小塊。如果您處於動態情況,記憶體不斷被分配和釋放,並且記憶體塊必須保持可用以隨機長度的時間,那麼這可能更加困難。

為了克服這些複雜情況,可以使用自動記憶體管理器系統,如垃圾收集器,來嘗試自動執行記憶體分配和釋放。

華夏公益教科書