一般Java在內存分配時會涉及到以下區域:
◆寄存器:我們在程序中無法控制
◆棧:存放基本類型的數據和對象的引用,但對象本身不存放在棧中,而是存放在堆中(new 出來的對象)
◆堆:存放用new產生的數據
◆靜態域:存放在對象中用static定義的靜態成員
◆常量池:存放常量
◆非RAM存儲:硬盤等永久存儲空間
棧:方法中定義的一些基本類型的變量數據和對象(和形式參數)的引用變量都在棧內存中分配,棧內存中的局部變量隨着方法的消失而消失。存在棧中的數據可以共享
堆:存放由new創建的對象和數組,由GC管理。棧中定義引用變量,其取值等於數組或對象在堆內存中的首地址。引用變量在程序運行到其作用域之外後被釋放。而數組和對象不會,他們只有在沒有引用變量指向它的時候纔會被GC在適當時機回收。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | class BirthDate { private int day; private int month; private int year; public BirthDate(int d, int m, int y) { day = d; month = m; year = y; } } public class Test{ public static void main(String args[]){ int date = 9; Test test = new Test(); test.change(date); BirthDate d1= new BirthDate(7,7,1970); } public void change1(int i){ i = 1234; } } |
下面分析一下代碼執行時候的變化:
1. main方法開始執行:int date = 9; date局部變量,基礎類型,引用和值都存在棧中。
2. Test test = new Test(); test爲對象引用,存在棧中,對象(new Test())存在堆中。
3. test.change(date); i爲局部變量,引用和值存在棧中。當方法change執行完成後,i就會從棧中消失。
4. BirthDate d1= new BirthDate(7,7,1970);d1 爲對象引用,存在棧中,對象(new BirthDate())存在堆中,其中d,m,y爲局部變量存儲在棧中,且它們的類型爲基礎類型,因此它們的數據也存儲在棧中。 day,month,year爲成員變量,它們存儲在堆中(new BirthDate()裏面)。當BirthDate構造方法執行完之後,d,m,y將從棧中消失。
5.main方法執行完之後,date變量,test,d1引用將從棧中消失,new Test(),new BirthDate()將等待垃圾回收。
常量池:常量池指在編譯期被確定,並被保存在已編譯的.class文件中的數據。
除了包含代碼中所定義的各種基本類型和對象型的常量值(final)還包含一些以文本形式出現的符號引用,比如:
◆類和接口的全限定名;
◆字段的名稱和描述符;
◆方法的名稱和描述符;
String類型在編譯期已經創建好(直接用雙引號定義的)的就存儲在常量池中,如果是運行期(new出來的)才能確定的就存儲在堆中。