中文原文:棧和堆的區別
英文原文:Memory:Stack vs Heaphtml
校對:xiaobai22git
目錄github
棧和堆的優缺點編程
到目前爲止,咱們已經知道如何聲明基礎變量類型,例如:int
,double
等以及複雜類型例如:數組和結構體。在C語言中,咱們使用和其餘語言諸如MATLAB,Python相同的語法聲明它們,並把這些變量推到棧裏。數組
什麼是棧?這是計算機內存的特定區域,它存儲每一個函數建立的臨時變量(包括main()
函數)。棧使用「LIFO」數據結構,由CPU管理和優化。每當函數聲明一個新變量,它就會被推入棧。當函數退出時,全部被該函數推入棧的變量會被釋放(這表明,它們已經被刪除)。一旦棧的變量釋放,此內存區能夠被其餘棧變量使用。數據結構
使用棧保存變量的優勢:CPU幫你管理內存。你不須要手動分配和釋放。更重要的是,CPU能夠高效的組織內存,讀寫棧變量會很是快。函數
理解棧的關鍵 :當函數退出時,它推入棧的全部變量會被彈出(永遠丟失)。棧變量本質是局部的。這涉及到咱們以前瞭解的 變量做用域 或 局部和全局變量。在C語言編程一般會遇到此類BUG:從函數外部企圖讀取函數內部的變量(在函數退出以後)。工具
棧另外一個須要注意的特徵是:保存在棧的變量是有大小限制的。堆的狀況卻不同。優化
棧的總結:操作系統
堆是計算機的內存區,它不會幫你自動管理,也不禁CPU管理。堆有更大的空間。你須要使用 C語言內置函數malloc()
和 calloc()
分配內存到堆。當再也不使用這塊內存時,你負責使用free()
進行釋放。若是沒作這步,你的程序會發生內存泄露。堆上的內存仍然被佔用(不能被其餘進程使用)。正如咱們在調試中看到的,用 valgrind
工具,幫助檢測內存泄漏。
和棧不同,堆沒有大小限制(除了物理內存限制)。堆的讀寫稍微比較慢,由於必須使用指針訪問堆上的內存。咱們在後面會討論指針。
和棧不同,其餘函數和你程序上的任何地方均可以訪問堆上建立的變量。堆本質是全局的。
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()
手動管理內存。咱們會討論動態分配數據結構在討論完指針後。