1. 程式人生 > >Java儲存機制——棧、堆的區別

Java儲存機制——棧、堆的區別

Java的6種儲存儲存地址及其解釋

  1. 暫存器(register):這是最快的儲存區,因為它位於不同於其他儲存區的地方——處理器內部。但是暫存器數量極其有限,所以暫存器根據編譯器需求來進行分配,我們無法控制。
  2. 堆疊(常稱為棧:stack):位於通用RAM中。它通過它的“堆疊指標”可以從處理器獲得支援。堆疊指標若是往下移動,則分配新的記憶體,堆疊指標若是往上移動,則釋放記憶體。這是一種快速有效的分配方法,僅次於暫存器。但是建立程式的時候,棧必須要知道儲存在棧內資料的大小和確切生命值,因為要根據程式生成程式碼,以便上下移動堆疊指標。雖然這種儲存方式快速,但是也失去了程式的靈活性,所以物件不存放在棧裡面。
  3. 堆(heap):位於通用性的記憶體池(也位於通用RAM)中,用於存放所有Java的物件。堆不同於棧的好處就是:堆不需要知道自己需要分配多少的記憶體區域,也不需要知道儲存的程式碼資料能夠成活多久,因此,堆的內記憶體分配有很大的的靈活性。當需要建立一個物件的時候,只需要new一個,執行這行程式碼的時候堆就會分配記憶體。但是堆也為了這個靈活性付出了代價的,因為是執行過程中才分配的記憶體,所以速度就比較慢,比棧要慢很多
  4. 靜態域(static storage):存放static定義的靜態成員,也是程式執行時一直存在的資料。這裡的靜態是指在固定的位置。
  5. 常量池(constant storage):存放常量(public static final
    ),即字串常量、基本資料資料常量。常存放於程式碼內部,因為不會被改變。
  6. 非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:

  1. 先定義一個名為str的String類的物件引用變數:String str;
  2. 在棧中查詢有沒有存放值為“abc”的地址,如果沒有,就開闢一個存放字面值為“abc”的地址,接著新建一個String的物件string指向該地址,在棧中這個地址旁記下這個引用的物件string。如果有值為“abc”的地址,則查詢物件string,並返回string的地址。
  3. 將str指向引用變數string的地址
  4. 也許你會覺得和  基本資料型別的引用  類似,沒錯就這麼理解吧。
		String str1 = "字串";
		String str3 = "字串";
		System.out.println(str1 == str3);//true
  • 這裡只建立了一個物件,但是兩個引用變數指向了這個物件。 

建立方式2:

  1. new出來的物件都存放在堆裡面,顯而易見,此時兩者已經地址已經不相等了
  2. 下面程式碼建立了三個物件,自行理解~
		String str1 = "字串";
		String str2 = new String("字串");
		String str3 = new String("字串");
		System.out.println(str1 == str2);//false
		System.out.println(str3 == str2);//false