Java堆內存與棧內存對比
阿新 • • 發佈:2018-03-02
sin runtime 一段 線程 全局 args public ng- error:
在數據結構中,堆和棧可以說是兩種最基礎的數據結構,而Java中的棧內存空間和堆內存空間有什麽異同,以及和數據結構中的堆棧有何關系?
一、Java 堆存儲空間
堆內存(堆存儲空間)會在Java運行時分配給對象(Object)或者JRE的類。只要我們創建了一個對象,那麽在堆中肯定會分配一塊存儲空間給這個對象。而我們熟知的Java垃圾回收就是在堆存儲空間上進行的,用以釋放那些沒有任何引用指向自身的對象。任何在堆中分配的對象都有全局訪問權限,而且可以從應用的任何地方被引用。
二、Java 棧存儲空間
Java 棧存儲空間用來供線程執行時使用。棧空間中包含特別的變量如:短生命周期和指向其他在堆中對象的引用。這裏棧存儲空間滿足後進先出的順序。當一個函數被調用時,會在棧中分配一塊新的存儲空間,用來存放函數的基本數據(【Java心得總結一】Java基本類型和包裝類型解析)以及在函數中對其它對象的引用。一旦函數執行結束,存儲空間就會被釋放供下一個函數使用。
棧存儲空間遠遠小於堆存儲空間
三、舉例
Memory.java
1 public class Memory { 2 3 public static void main(String[] args) { // Line 1 4 int i=1; // Line 2 5 Object obj = new Object(); // Line 3 6 Memory mem = new Memory(); // Line 4 7 mem.foo(obj); // Line 5 8 } // Line 9 9 10 private void foo(Object param) { // Line 6 11 String str = param.toString(); //// Line 7 12 System.out.println(str); 13 } // Line 8 14 15 }
下圖展示了堆棧存儲空間是如何存儲基本類型、對象以及指向變量的引用
程序執行過程:
- 一旦我們開始運行程序,它會將所有運行時類裝載入堆存儲空間。當程序運行至第一行main()函數,Java Runtime會為主函數線程分配棧存儲空間。
- 我們在第二行創建了基本數據類型,所以它會被存儲在主函數線程的棧存儲空間;
- 因為我們在第三行創建了Object對象,它會在堆中被創建,並且棧空間中保存有指向它的引用。同理第四行創建Memory對象。
- 當我們在main()主函數第五行調用foo()函數時,在棧空間頂部會分配一塊空間給foo()函數使用。因為Java是值傳遞(Java 為值傳遞而不是引用傳遞),在foo函數第六行中會有一個新的引用被創建指向堆中的Object對象
- 在第7行創建了一個字符串,它會被放在堆空間的字符串池中(String Poll),而且在棧空間中會保存一個指向它的引用
- 在第8行foo函數執行完畢,此時其棧空間會被釋放
- 在第9行main函數執行完畢,棧中分配給main函數的空間會被釋放。同時程序也在這一行執行完畢,因此Java運行時(Java Runtime)會釋放所有內存空間並且終止程序的執行。
四、堆棧異同
- 堆存儲空間可以被應用的任何部分使用,然而棧存儲空間只能被對應的執行線程使用
- 一旦對象被建立,那麽就會在堆中分配一段存儲空間而棧空間中保留有對它的引用。棧空間中僅僅保存基本數據類型和指向堆中對象的引用變量
- 堆中存儲的對象可以被全局訪問,然而棧中存儲的變量不能被其它線程(函數)訪問
- 棧中的內存管理采用先進後出的(LIFO)的方式,然而在堆中內存管理會更為復雜,因為堆中的對象可以被全局使用。對存儲空間被分為Young-Generation,Old-Generation等,這個我會在之後總結
- 棧存儲空間是短生命周期的,然而堆存儲要長的多
- 利用-Xms和-Xmx來指明JVM的堆初始空間和最大空間,利用-Xss來定義棧空間大小
- 當棧空間滿了,Java運行時會拋出 java.lang.StackOverFlowError ,然而堆空間滿了,拋出的是 java.lang.OutOfMemoryError: Java Heap Space 錯誤
- 棧空間相比較於堆空間是非常小的,又因為棧中使用最簡單的先進後出(LIFO)原則,它是遠遠快於堆的。
參考:https://www.cnblogs.com/xltcjylove/p/4502859.html
Java堆內存與棧內存對比