[譯]棧和堆的區別

棧和堆的區別

中文原文:棧和堆的區別
英文原文:Memory:Stack vs Heaphtml

校對:xiaobai22git

目錄github

  • 棧和堆的區別
  • 棧和堆的優缺點編程

  • 例子
  • 何時使用堆
  • 關聯文章

棧和堆的區別

到目前爲止,咱們已經知道如何聲明基礎變量類型,例如:int,double 等以及複雜類型例如:數組和結構體。在C語言中,咱們使用和其餘語言諸如MATLAB,Python相同的語法聲明它們,並把這些變量推到棧裏。數組

什麼是棧?這是計算機內存的特定區域,它存儲每一個函數建立的臨時變量(包括main() 函數)。棧使用「LIFO」數據結構,由CPU管理和優化。每當函數聲明一個新變量,它就會被推入棧。當函數退出時,全部被該函數推入棧的變量會被釋放(這表明,它們已經被刪除)。一旦棧的變量釋放,此內存區能夠被其餘棧變量使用。數據結構

使用棧保存變量的優勢:CPU幫你管理內存。你不須要手動分配和釋放。更重要的是,CPU能夠高效的組織內存,讀寫棧變量會很是快。函數

理解棧的關鍵 :當函數退出時,它推入棧的全部變量會被彈出(永遠丟失)。棧變量本質是局部的。這涉及到咱們以前瞭解的 變量做用域 或 局部和全局變量。在C語言編程一般會遇到此類BUG:從函數外部企圖讀取函數內部的變量(在函數退出以後)。工具

棧另外一個須要注意的特徵是:保存在棧的變量是有大小限制的。堆的狀況卻不同。優化

棧的總結:操作系統

  • 棧的增加和縮容發生在函數推入和彈出局部變量時
  • 不須要你本身管理內存,變量會自動分配和釋放
  • 棧有大小限制
  • 棧變量僅存在於建立它們的函數運行的時候

堆是計算機的內存區,它不會幫你自動管理,也不禁CPU管理。堆有更大的空間。你須要使用 C語言內置函數malloc()calloc() 分配內存到堆。當再也不使用這塊內存時,你負責使用free()進行釋放。若是沒作這步,你的程序會發生內存泄露。堆上的內存仍然被佔用(不能被其餘進程使用)。正如咱們在調試中看到的,用 valgrind工具,幫助檢測內存泄漏。

和棧不同,堆沒有大小限制(除了物理內存限制)。堆的讀寫稍微比較慢,由於必須使用指針訪問堆上的內存。咱們在後面會討論指針。

和棧不同,其餘函數和你程序上的任何地方均可以訪問堆上建立的變量。堆本質是全局的。

棧和堆的優缺點

  • 訪問很是快
  • 沒必要顯式的分配變量
  • CPU有效的管理,不會產生內存碎片
  • 僅用於局部變量
  • 有大小限制(不一樣操做系統有區別)
  • 大小不能被調整

  • 變量能夠全局訪問
  • 沒有內存限制
  • (相對的)訪問速度比較慢
  • 會產生內存碎片
  • 須要你分配和釋放
  • 大小能夠經過 realloc() 調整

例子

這是一個簡短的程序,建立變量到棧。

#include 

double multiplyByTwo (double input) {
  double twice = input * 2.0;
  return twice;
}

int main (int argc, char *argv[])
{
  int age = 30;
  double salary = 12345.67;
  double myList[3] = {1.2, 2.3, 3.4};

  printf("double your salary is %.3f\n", multiplyByTwo(salary));

  return 0;
}
double your salary is 24691.340

在10,11,12行咱們聲明瞭變量:int ,double,長度爲3的浮點型數組。main() 進行分配的時候,這3個變量被推到棧。當main() 函數退出(程序中止),這些變量會被彈出棧。一樣的,在函數 multiplyByTwo() 有2個 double 型的變量,會被推到棧。multiplyByTwo() 退出,這2個變量會被彈出棧,永遠消失。

順便提一句,有一種方法能夠告訴C語言,即便建立函數退出後,仍然能夠保留棧變量,就是在聲明變量時使用 static 關鍵字。所以,使用 static 關鍵字聲明的變量相似於全局變量,但只能在建立它的函數中可見。這是一種奇怪的結構,除非在很是特殊的狀況下,不然你可能不須要它

這是另外一個版本,分配全部變量到堆而不是棧:

#include 
#include 

double *multiplyByTwo (double *input) {
  double *twice = malloc(sizeof(double));
  *twice = *input * 2.0;
  return twice;
}

int main (int argc, char *argv[])
{
  int *age = malloc(sizeof(int));
  *age = 30;
  double *salary = malloc(sizeof(double));
  *salary = 12345.67;
  double *myList = malloc(3 * sizeof(double));
  myList[0] = 1.2;
  myList[1] = 2.3;
  myList[2] = 3.4;

  double *twiceSalary = multiplyByTwo(salary);

  printf("double your salary is %.3f\n", *twiceSalary);

  free(age);
  free(salary);
  free(myList);
  free(twiceSalary);

  return 0;
}

正如你所看到的,使用 malloc() 分配內存到堆和使用 free() 釋放,這不是大問題,但有點麻煩。另一個須要注意的是處處都是星符號。它們是什麼?答案是,它們是指針。malloc() 處理指針,而不是真實的值。咱們後面會更詳細討論指針。指針在C語言是一種特殊的數據類型,它保存地址在內存而不是真實的值。所以在上面第5行,2個變量都不是 double , 但它們是指向浮點型的指針。變量double 保存了一個地址在內存。

何時使用堆

何時使用堆?何時使用棧?若是你要分配一塊大內存和你須要保留這個變變量很長時間,那麼你就要分配它們到堆。若是你處理的是相對小的變量,只須要存活在函數使用期間,那麼你可使用棧,它更容易更快。若是你須要能夠動態改變大小的變量例如:數據和結構體,那你須要分配它們到堆,用動態內存分配函數 mallco() calloc() realloc()free()手動管理內存。咱們會討論動態分配數據結構在討論完指針後。

相關連接

The Stack and the Heap

What and Where are the stack and heap

相關文章
相關標籤/搜索