堆和棧的區別


引言

    今天的Java課上,老師中途說,String是不可變類型,比較的是堆的內容還是棧的內容?這里當然是堆的內容啦,棧只是臨時操作。

我忽然聯想到了堆和棧的區別,一般來說,“堆棧”指的是棧,而不是堆,那么棧和堆有什么區別呢?下面我們就細細說來。

 

概述:

    在計算機領域堆和棧是非常重要的概念,在數據結構中,堆和棧是兩種完全不同的數據結構,

1. 棧:先進后出(FILO—First-In/Last-Out)。且只能在一端進行插入、刪除操作,這一端我們稱為棧頂(Top)。

2. 堆:隊列優先,先進先出(FIFO—firstinfirstout)。

 

看圖說話

                                                                                                                                                      堆棧圖1

 

    此時棧中的字符串str3、str4分別在堆中“開辟”了兩片新空間,對應兩個String("123"),random和random1也是如此1,由此圖我們可以想象一下:

棧中的成員排隊進入堆中,棧還是未確定的棧,有可能還會進行增刪操作,比如把str3像str1、str2一樣刪除了,那么,先出去的是誰呢?

肯定是str2啦,也就是我們開頭講的棧是“先進后出”的原則,由此也可以引出我們老師的話:String比較的是堆,而不是棧,棧相當於江湖“客棧”,

大俠們來來往往,住的人和數是可以改變的。

 

棧和堆的對比:

    1. 堆棧空間的分配:

      棧(操作系統):由操作系統自動分配釋放,存放函數的參數值,局部變量的值等。其操作方式類似於數據結構中的棧。

      堆(操作系統):一般由程序員分配釋放,若程序員不釋放,程序結束時可能由OS回收,分配方式類似於鏈表

      2. 堆棧緩存方式:

  棧使用的是一級緩存,他們通常都是被調用時處於存儲空間中,調用完畢立即釋放。

  堆則是存放在二級緩存中,生命周期由虛擬機的垃圾回收算法來決定(並不是一旦成為孤兒對象就能被回收)。所以調用這些對象的速度要相對來得低一些。

  3、堆棧數據結構區別

  堆(數據結構):堆可以被看成是一棵樹,如:堆排序。

  棧(數據結構):一種先進后出的數據結構。

一文看懂堆和棧的區別和聯系

  堆和棧的聯系

  主函數先進棧,在棧中定義一個變量arr,接下來為arr賦值,但是右邊不是一個具體值,是一個實體。實體創建在堆里,在堆里首先通過new關鍵字開辟一個空間,內存在存儲數據的時候都是通過地址來體現的,地址是一塊連續的二進制,然后給這個實體分配一個內存地址。數組都是有一個索引,數組這個實體在堆內存中產生之后每一個空間都會進行默認的初始化(這是堆內存的特點,未初始化的數據是不能用的,但在堆里是可以用的,因為初始化過了,但是在棧里沒有),不同的類型初始化的值不一樣。所以堆和棧里就創建了變量和實體:

一文看懂堆和棧的區別和聯系

  給堆分配了一個地址,把堆的地址賦給arr,arr就通過地址指向了數組。所以arr想操縱數組時,就通過地址,而不是直接把實體都賦給它。這種我們不再叫他基本數據類型,而叫引用數據類型。稱為arr引用了堆內存當中的實體。(可以理解為c或c++的指針,Java成長自c++和c++很像,優化了c++)

  如果當int[]arr=null;

  arr不做任何指向,null的作用就是取消引用數據類型的指向。

  當一個實體,沒有引用數據類型指向的時候,它在堆內存中不會被釋放,而被當做一個垃圾,在不定時的時間內自動回收,因為Java有一個自動回收機制,(而c++沒有,需要程序員手動回收,如果不回收就越堆越多,直到撐滿內存溢出,所以Java在內存管理上優於c++)。自動回收機制(程序)自動監測堆里是否有垃圾,如果有,就會自動的做垃圾回收的動作,但是什么時候收不一定。

  所以堆與棧的區別很明顯:

  1.棧內存存儲的是局部變量而堆內存存儲的是實體;

  2.棧內存的更新速度要快於堆內存,因為局部變量的生命周期很短;

  3.棧內存存放的變量生命周期一旦結束就會被釋放,而堆內存存放的實體會被垃圾回收機制不定時的回收。

  堆與棧的主要區別

                                                                 

                                                                                                                                      棧詳解圖

 

 

 

                                                                                                                          堆詳解圖

 

區別總結:

 

  1、管理方式:對於棧來講,是由編譯器自動管理,無需我們手工控制;對於堆來說,釋放工作由程序員控制,容易產生memoryleak。

  2、空間大小:一般來講在32位系統下,堆內存可以達到4G的空間,從這個角度來看堆內存幾乎是沒有什么限制的。但是對於棧來講,一般都是有一定的空間大小的,例如,在VC6下面,默認的棧空間大小是1M(好像是,記不清楚了)。當然,我們可以修改:

  注意:reserve最小值為4Byte;commit是保留在虛擬內存的頁文件里面,它設置的較大會使棧開辟較大的值,可能增加內存的開銷和啟動時間。

  4、碎片問題:對於堆來講,頻繁的new/delete勢必會造成內存空間的不連續,從而造成大量的碎片,使程序效率降低。對於棧來講,則不會存在這個問題,因為棧是先進后出的隊列,他們是如此的一一對應,以至於永遠都不可能有一個內存塊從棧中間彈出,在他彈出之前,在他上面的后進的棧內容已經被彈出,詳細的可以參考數據結構,這里我們就不再一一討論了。

  5、生長方向:對於堆來講,生長方向是向上的,也就是向着內存地址增加的方向;對於棧來講,它的生長方向是向下的,是向着內存地址減小的方向增長。

  6、分配方式:堆都是動態分配的,沒有靜態分配的堆。棧有2種分配方式:靜態分配和動態分配。靜態分配是編譯器完成的,比如局部變量的分配。動態分配由alloca函數進行分配,但是棧的動態分配和堆是不同的,他的動態分配是由編譯器進行釋放,無需我們手工實現。

  7、分配效率:棧是機器系統提供的數據結構,計算機會在底層對棧提供支持:分配專門的寄存器存放棧的地址,壓棧出棧都有專門的指令執行,這就決定了棧的效率比較高。堆則是C/C++函數庫提供的,它的機制是很復雜的,例如為了分配一塊內存,庫函數會按照一定的算法(具體的算法可以參考數據結構/操作系統)在堆內存中搜索可用的足夠大小的空間,如果沒有足夠大小的空間(可能是由於內存碎片太多),就有可能調用系統功能去增加程序數據段的內存空間,這樣就有機會分到足夠大小的內存,然后進行返回。顯然,堆的效率比棧要低得多。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM