1. 程式人生 > >Java的記憶體機制(堆和棧)簡單理解

Java的記憶體機制(堆和棧)簡單理解

偶然看到一道面試題,Java在例項化一個類的時候,資料在堆和棧中是如何存放的?

public class A{
    public int i=1;
    public static A a1 = new A();
    public static void mian(String args[]){
      int c = 2;
      A a=new A();
    }
}

答案是:
處於棧中的資料:A物件的引用a和區域性變數c
處於堆中的資料:變數a所指向的物件,變數a1所指向的物件,成員變數i,靜態變數a1

Java的記憶體機制

Java把記憶體分為堆記憶體和棧記憶體兩個部分

棧記憶體:

函式中定義的基本資料型別的變數和物件的引用都存放在棧記憶體,當在一個函式中定義一個變數時,java就在棧中為該變數分配記憶體空間,當這個變數被用完之後(超過了變數的作用域),java會自動釋放掉為該變數分配的記憶體。因此我們可以這樣理解,對於一個區域性變數,如果它是一個基本資料型別,那麼這個變數存放在棧中;如果這個變數是一個物件,那麼該物件存放在堆中,而物件的引用仍然在棧中!

堆記憶體:

堆記憶體用來存放由 new 建立的物件和陣列,所有的成員變數和static修飾的類變數,在堆中分配的記憶體,由 Java 虛擬機器的自動垃圾回收器來管理。
當物件的引用在位於棧中時,棧中的這個引用的取值等於陣列或物件在堆記憶體中的首地址,棧中的這個變數就成了陣列或物件的引用變數,以後就可以在程式中使用棧中的引用變數來訪問堆中的陣列或者物件,引用變數就相當於是為陣列或者物件起的一個名稱。引用變數是普通的變數,定義時在棧中分配,引用變數在程式執行到其作用域之外後被釋放。而陣列和物件本身在堆中分配,即使程式執行到使用 new 產生陣列或者物件的語句所在的程式碼塊之外,陣列和物件本身佔據的記憶體不會被釋放,陣列和物件在沒有引用變數指向它的時候,才變為垃圾,不能在被使用,但仍然佔據記憶體空間不放,在隨後的一個不確定的時間被垃圾回收器收走(釋放掉)。