Java 堆棧內存分配

很多人在Java的書籍中看到過很多關於堆和棧內存的教程以及參考說明, 但是很難解釋什麼是程序的堆內存以及棧內存

一: Java 堆內存空間

Java程序運行時使用java Heap 內存爲對象以及JRE類分配內存, 不論我們在何時創建何種類型的對象, 他總是在堆內存中創建的

Java 垃圾收集器運行在堆內容空間, 釋放那些沒有任何引用的對象所使用的內存。 在堆內存空間創建的任何對象都具有全局訪問權限, 並且可以從程序的任何位置引用

二: Java 棧內存空間

Java 棧內存空間用於執行線程, 棧內存始終遵循LIFO(Last-in-first-out) 順序, 每當一個方法被執行, 會在棧內存中創建一個新的block 用於保存在函數中定義的基本數據類型變量以及對象的引用變量

當方法結束時, this block 改變它的狀態爲未使用並且可用於執行下一個方法

堆內存大小與堆內存相比非常少。

三: Java程序中的堆和堆棧內存

通過一個簡單的程序來理解堆 棧內存的使用情況

/**
 * Created by huanjulu on 12/10/17.
 */

public class HeapStackTestMemory {

    public static void main(String[] args) { //Line 1

        int i = 1; //Line 2

        Object obj = new Object(); //Line 3

        HeapStackTestMemory mem = new HeapStackTestMemory(); //Line 4

        mem.foo(obj);  //Line 5

    }  //Line 9

    private void foo(Object param) {  //Line 6

        String str = param.toString();  //Line 7

        System.out.println(str);

    } //Line 8

}

參考上面的java 程序, 下圖顯示了stack Heap 內存空間的使用情況

我們來看看執行程序的步驟。

  • 一旦我們開始運行程序, 它會把所有的運行時類加載到堆內存空間, 在 Line 1 行找到main() 方法, Java Runtime 創建由main() 方法線程使用的棧內存空間
  • 在第二行 我們創建了原始數據類型的局部變量, 所以它將被存儲在main() 方法的棧內存空間
  • 在第3行我們創建了一個Object 類型的對象, 所以它被創建在Heap 堆內存空間中 並且 Stack 棧內存空間包含對它的引用, 當我們在第4行中創建Memory 對象時, 會發生類似的過程
  • 現在我們在第5行調用foo() 方法, 此時會在stack 棧創建一個block 供foo() 方法使用
  • Java 是通過值傳遞, 在第6行, 會在foo() 棧中創建一個對Object 對象的新的引用
  • 在第7行 , 一個string 類型的對象被創建, 此時 會在foo() 棧內存中創建它的一個引用 str
  • foo() 方法在第8行執行完畢, 此時, 程序會釋放stack 棧內存中爲foo() 方法分配的棧內存空間
  • 在第9行, main() 方法執行完畢, 爲main()方法創建的堆棧內存被銷燬, 此時 這個java 程序結束運行, Java Runtime 會釋放所有的內存

     
    四: Java Heap Difference with Stack Memory Space

基於上述的說明, 可以很容易的總結出堆棧內存的以下差異

1, 堆內存屬於java 應用程序所使用, 棧內存屬於線程所私有的, 它的生命週期與線程相同
2, 不論何時創建一個對象, 它總是存儲在堆內存空間 並且棧內存空間包含對它的引用 . 棧內存空間只包含方法原始數據類型局部變量以及堆空間中對象的引用變量
3, 在堆中的對象可以全局訪問, 棧內存空間屬於線程所私有
4, jvm 棧內存結構管理較爲簡單, 遵循LIFO 的原則, 堆空間內存管理較爲複雜 , 細分爲:新生代和老年代 etc..
5, 棧內存生命週期短暫, 而堆內存伴隨整個用用程序的生命週期
6, 二者拋出異常的方式, 如果線程請求的棧深度大於虛擬機所允許的深度,將拋出StackOverflowError異常, 堆內存拋出OutOfMemoryError異常

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章