Java堆和棧的區別和介紹,JVM的堆和棧

來源:互聯網
上載者:User

標籤:short   封裝   lang   text   狀態   出現   ble   事先   原因   

一、Java的堆記憶體和棧記憶體Java把記憶體劃分成兩種:一種是堆記憶體,一種是棧記憶體。 堆:主要用於儲存執行個體化的對象,數組。由JVM動態分配記憶體空間。一個JVM只有一個堆記憶體,線程是可以共用資料的。 棧:主要用於儲存局部變數和對象的引用變數,每個線程都會有一個獨立的棧空間,所以線程之間是不共用資料的。 在函數中定義的一些基本類型的變數和對象的引用變數都在函數的棧記憶體中分配。 當在一段代碼塊定義一個變數時,Java就在棧中為這個變數分配記憶體空間,當超過變數的範圍後,Java會自動釋放掉為該變數所分配的記憶體空間,該記憶體空間可以立即被另作他用。
 堆記憶體用來存放由new建立的對象和數組。在堆中分配的記憶體,由Java虛擬機器的自動記憶體回收行程來管理。
  二、棧與堆的共同點和優缺點
 1. 棧(stack)與堆(heap)都是Java用來在Ram中存放資料的地方。與C++不同,Java自動管理棧和堆,程式員不能直接地設定棧或堆。
 2. 棧的優勢是,存取速度比堆要快,僅次於直接位於CPU中的寄存器。但缺點是,存在棧中的資料大小與生存期必須是確定的,缺乏靈活性。另外,棧資料可以共用,詳見第3點。堆的優勢是可以動態地分配記憶體大小,生存期也不必事先告訴編譯器,Java的垃圾收集器會自動收走這些不再使用的資料。但缺點是,由於要在運行時動態分配記憶體,存取速度較慢。
 3. Java中的資料類型有兩種。

一種是基本類型(primitive types), 共有8種,即int, short, long, byte, float, double, boolean, char(注意,並沒有string的基本類型)。這種類型的定義是通過諸如int a = 3; long b = 255L;的形式來定義的,稱為自動變數。值得注意的是,自動變數存的是字面值,不是類的執行個體,即不是類的引用,這裡並沒有類的存在。如int a = 3; 這裡的a是一個指向int類型的引用,指向3這個字面值。這些字面值的資料,由於大小可知,生存期可知(這些字面值固定定義在某個程式塊裡面,程式塊退出後,欄位值就消失了),出於追求速度的原因,就存在於棧中。
 棧有一個很重要的特殊性,就是存在棧中的資料可以共用。

假設我們同時定義 int a = 3; int b = 3;編譯器先處理int a = 3;首先它會在棧中建立一個變數為a的引用,然後尋找有沒有字面值為3的地址,沒找到,就開闢一個存放3這個字面值的地址,然後將a指向3的地址。接著處理int b = 3;在建立完b的引用變數後,由於在棧中已經有3這個字面值,便將b直接指向3的地址。這樣,就出現了a與b同時均指向3的情況。特別注意的是,這種字面值的引用與類對象的引用不同。假定兩個類對象的引用同時指向一個對象,如果一個對象引用變數修改了這個對象的內部狀態,那麼另一個對象引用變數也即刻反映出這個變化。相反,通過字面值的引用來修改其值,不會導致另一個指向此字面值的引用的值也跟著改變的情況。如上例,我們定義完a與 b的值後,再令a=4;那麼,b不會等於4,還是等於3。在編譯器內部,遇到a=4;時,它就會重新搜尋棧中是否有4的字面值,如果沒有,重新開闢地址存放4的值;如果已經有了,則直接將a指向這個地址。因此a值的改變不會影響到b的值。
 另一種是封裝類資料,如Integer, String, Double等將相應的基礎資料型別 (Elementary Data Type)封裝起來的類。這些類資料全部存在於堆中,Java用new()語句來顯式地告訴編譯器,在運行時才根據需要動態建立,因此比較靈活,但缺點是要佔用更多的時間。上海尚學堂java培訓。
  三、Java堆和棧的區別

 

java中堆和棧的區別自然是面試中的常見問題,下面幾點就是其具體的區別  1、各司其職最主要的區別就是棧記憶體用來儲存局部變數和方法調用。而堆記憶體用來儲存Java中的對象。無論是成員變數,局部變數,還是類變數,它們指向的對象都儲存在堆記憶體中。  2、專屬還是共用棧記憶體歸屬於單個線程,每個線程都會有一個棧記憶體,其儲存的變數只能在其所屬線程中可見,即棧記憶體可以理解成線程的私人記憶體。而堆記憶體中的對象對所有線程可見。堆記憶體中的對象可以被所有線程訪問。  3、異常錯誤如果棧記憶體沒有可用的空間儲存方法調用和局部變數,JVM會拋出java.lang.StackOverFlowError。而如果是堆記憶體沒有可用的空間儲存產生的對象,JVM會拋出java.lang.OutOfMemoryError。
4、空間大小棧的記憶體要遠遠小於堆記憶體,如果你使用遞迴的話,那麼你的棧很快就會充滿。如果遞迴沒有及時跳出,很可能發生StackOverFlowError問題。
 你可以通過-Xss選項設定棧記憶體的大小。-Xms選項可以設定堆的開始時的大小,-Xmx選項可以設定堆的最大值。 這就是Java中堆和棧的區別。理解好這個問題的話,可以對你解決開發中的問題,分析堆記憶體和棧記憶體使用量,甚至效能調優都有協助。
四、JVM中的堆和棧JVM是基於堆棧的虛擬機器.JVM為每個新建立的線程都分配一個堆棧.也就是說,對於一個Java程式來說,它的運行就是通過對堆棧的操作來完成的。堆棧以幀為單位儲存線程的狀態。JVM對堆棧只進行兩種操作:以幀為單位的壓棧和出棧操作。 我們知道,某個線程正在執行的方法稱為此線程的當前方法.我們可能不知道,當前方法使用的幀稱為當前幀。當線程啟用一個Java方法,JVM就會線上程的 Java堆棧裡新壓入一個幀。這個幀自然成為了當前幀.在此方法執行期間,這個幀將用來儲存參數,局部變數,中間計算過程和其他資料.這個幀在這裡和編譯原理中的活動紀錄的概念是差不多的. 從Java的這種分配機制來看,堆棧又可以這樣理解:堆棧(Stack)是作業系統在建立某個進程時或者線程(在支援多線程的作業系統中是線程)為這個線程建立的儲存地區,該地區具有先進後出的特性。

每一個Java應用都唯一對應一個JVM執行個體,每一個執行個體唯一對應一個堆。應用程式在運行中所建立的所有類執行個體或數組都放在這個堆中,並由應用所有的線程 共用.跟C/C++不同,Java中分配堆記憶體是自動初始化的。Java中所有對象的儲存空間都是在堆中分配的,但是這個對象的引用卻是在堆棧中分配,也就是說在建立一個對象時從兩個地方都分配記憶體,在堆中分配的記憶體實際建立這個對象,而在堆棧中分配的記憶體只是一個指向這個堆對象的指標(引用)而已。

Java 把記憶體劃分成兩種:一種是棧記憶體,另一種是堆記憶體。在函數中定義的一些基本類型的變數和對象的引用變數都是在函數的棧記憶體中分配,當在一段代碼塊定義一個變數時,Java 就在棧中為這個變數分配記憶體空間,當超過變數的範圍後,Java 會自動釋放掉為該變數分配的記憶體空間,該記憶體空間可以立即被另作它用。

 


      (圖:JVM運行時資料區域分析)

 上海尚學堂 java培訓整理編輯,歡迎以下推薦內容或擷取學習資料與支援人員:

《【上海java培訓】Java記憶體地區、分配機制和GC記憶體回收演算法》;
《【上海Java培訓】Java虛擬機器類初始化和類載入器》;
《【上海Java培訓】Java基礎資料型別 (Elementary Data Type)和存放位置》

Java堆和棧的區別和介紹,JVM的堆和棧

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.