Java儲存機制——棧、堆的區別
阿新 • • 發佈:2018-12-13
Java的6種儲存儲存地址及其解釋
- 暫存器(register):這是最快的儲存區,因為它位於不同於其他儲存區的地方——處理器內部。但是暫存器數量極其有限,所以暫存器根據編譯器需求來進行分配,我們無法控制。
- 堆疊(常稱為棧:stack):位於通用RAM中。它通過它的“堆疊指標”可以從處理器獲得支援。堆疊指標若是往下移動,則分配新的記憶體,堆疊指標若是往上移動,則釋放記憶體。這是一種快速有效的分配方法,僅次於暫存器。但是建立程式的時候,棧必須要知道儲存在棧內資料的大小和確切生命值,因為要根據程式生成程式碼,以便上下移動堆疊指標。雖然這種儲存方式快速,但是也失去了程式的靈活性,所以物件不存放在棧裡面。
- 堆(heap):位於通用性的記憶體池(也位於通用RAM)中,用於存放所有Java的物件。堆不同於棧的好處就是:堆不需要知道自己需要分配多少的記憶體區域,也不需要知道儲存的程式碼資料能夠成活多久,因此,堆的內記憶體分配有很大的的靈活性。當需要建立一個物件的時候,只需要new一個,執行這行程式碼的時候堆就會分配記憶體。但是堆也為了這個靈活性付出了代價的,因為是執行過程中才分配的記憶體,所以速度就比較慢,比棧要慢很多。
- 靜態域(static storage):存放static定義的靜態成員,也是程式執行時一直存在的資料。這裡的靜態是指在固定的位置。
- 常量池(constant storage):存放常量(public static final
- 非RAM儲存:磁碟等永久儲存空間
堆、棧、方法區的的儲存內容
棧:
- 每個執行緒都包含一個棧區,棧中只包含基本資料型別的值、物件和基本資料型別的引用。
- 每個棧中的資料(基本資料型別和物件引用)都是私有的,其他棧不能訪問
堆:
- 儲存的全部是例項物件
- JVM只有一個堆被所有執行緒共享
方法區:
- 也叫靜態區,和堆一樣被所有執行緒共享。
- 方法區包含的都是整個程式永遠唯一的元素,如class變數,static變數
棧有一個很重要的特殊性,就是存在棧中的資料可以共享。假如同時定義
int a = 1; int b = 1;
編譯器先處理int a = 1;首先在棧中建立一個int型的變數,然後查詢有沒有字面值為1的地址。如果沒有找到,就開闢一個存放字面值為1的地址,然後a指向1的地址。在建立完a以後,已經存在字面值為1的地址,變數b在棧中找到字面值為1的地址,指向該地址。於是a,b同時指向1。這就是共享。
但是這種引用又與物件引用不相同。通過字面值的引用來修改值,不會導致另一個指向該字面值的引用的值也跟著改變。說起來比較拗口。下面解釋一下
int i1 = 9;
int i2 = 9;
int i3 = 9;
public static final int INT1 = 9;
public static final int INT2 = 9;
public static final int INT3 = 9;
當將i2賦值7的時候
i2 = 7;
會繼續上面的步驟,在棧中查詢有沒有字面值為7的地址。如果沒有,在棧中開闢一個字面值為7的地址,然後i2指向7的地址,因此不會影響其他引用。
提一下String類,這是一個特殊的包裝類資料。
區別一下兩種建立方式
1.String str = "abc";
2.String str = new String("abc");
建立方式1:
- 先定義一個名為str的String類的物件引用變數:String str;
- 在棧中查詢有沒有存放值為“abc”的地址,如果沒有,就開闢一個存放字面值為“abc”的地址,接著新建一個String的物件string指向該地址,在棧中這個地址旁記下這個引用的物件string。如果有值為“abc”的地址,則查詢物件string,並返回string的地址。
- 將str指向引用變數string的地址
- 也許你會覺得和 基本資料型別的引用 類似,沒錯就這麼理解吧。
String str1 = "字串";
String str3 = "字串";
System.out.println(str1 == str3);//true
- 這裡只建立了一個物件,但是兩個引用變數指向了這個物件。
建立方式2:
- new出來的物件都存放在堆裡面,顯而易見,此時兩者已經地址已經不相等了
- 下面程式碼建立了三個物件,自行理解~
String str1 = "字串";
String str2 = new String("字串");
String str3 = new String("字串");
System.out.println(str1 == str2);//false
System.out.println(str3 == str2);//false