1. 程式人生 > >java你可能不知道的事(2)--堆和棧

java你可能不知道的事(2)--堆和棧

在java語言的學習和使用當中你可能已經瞭解或者知道堆和棧,但是你可能沒有完全的理解它們。今天我們就一起來學習堆、棧的特點以及它們的區別。認識了這個之後,你可能對java有更深的理解。

Java堆記憶體(Heap Memory)

堆記憶體在Java執行時主要去回收物件和JRE的類。當我們建立了一個物件(也就是 new一個物件),在堆記憶體就會為物件分配一個空間,Java垃圾回收器(GC)執行在堆記憶體裡,一旦發現沒有任何地方引用到這個物件,就釋放這個物件所佔的記憶體。
被建立的物件存在於堆記憶體,並且擁有全域性許可權,能被應用的任何地方引用到。

Java棧記憶體(Stack Memory)

堆記憶體是單執行緒執行的,它的空間比堆記憶體空間要小。它裡面會包括定義在方法裡的、短時間存在的區域性變數,這些區域性變數總是引用到堆記憶體的物件。堆記憶體還有個特點就是後進先出。當一個方法被呼叫之後,在棧記憶體就會為這個方法產生一個記憶體區域來儲存方法裡的基本資料型別資料和引用了堆記憶體中物件的區域性變數。當這個方法執行完畢,這個塊沒有用了,就會被垃圾回收器回收,接著繼續下一個方法。

加深理解

先來看一段簡單的程式碼

public class TestMemory {

    public static void main(String[] args) {
        int
i = 666;//line1 Object object = new Object();//line2 TestMemory testMemory = new TestMemory();//line3 testMemory.test(object);//line4 } //line5 private void test(Object params){//line6 String str = params.toString();//line7 System.out.println(str);//line8 } } //line9

下面這張圖片展示了上面程式碼的記憶體資訊。

這裡寫圖片描述

1、當程式執行時,JVM會先載入執行時的類和我們自己寫的類資訊,這些類資訊載入後存在堆記憶體當中。

2、接著進入到main方法,第一行line1建立了一個基本資料型別i=666,所以建立了一個main方法的記憶體塊,它裡面同時存放了i=666;

3、接著line2和line3的位置
Object object = new Object();
TestMemory testMemory = new TestMemory();建立了兩個區域性變數,object和testMemory,同時在堆裡存放了兩個新的物件Object和TestMemory。(每次我們new 一個物件都會在堆區產生一塊記憶體區給它分配空間)。同時object和testMemory引用了new出來的物件。

4、現在到了line4,test方法了,當呼叫到test方法的時候,在棧的頂層建立了一塊test()方法的記憶體區(我們說過棧的特點就是後進先出),由於在 Java裡的傳遞是值傳遞,所以就有了引數object產生了一個新的引用。

5、最後呼叫了toString產生了一個字串常量存放在了String pool裡,並且str 引用了它。(如果你有String類感興趣,你可能喜歡 》 Java你可能不知道的事系列1_String類

6、當test方法結束,它裡面的變數也就被GC回收掉了。接著main方法也就結束。Java在執行時釋放這些記憶體並結束程式的執行。

總結

1、當一個物件被建立,總是會在堆記憶體為它分配空間並且儲存,如果有賦值就會將變數引用到物件。而棧記憶體就是存放這些引用物件的區域性變數。

2、棧記憶體的生命週期很短,而堆記憶體從程式執行開始到結束一隻都需要工作。因為棧記憶體沒當執行完一個方法,它們所佔的記憶體區就會被釋放。而堆記憶體裡的物件只有在沒有任何變數引用到它的時候才可能會被釋放。

3、棧記憶體大小相比於堆記憶體非常小。但是它相對於堆記憶體又比較快。