Java內存分析

我們常說的Java內存主要分爲四大塊(寄存器不在考慮之內,我們無法用代碼來操控它):stack(棧)、heap(堆)、data segment(數據區)、code segment(代碼區)。它們的主要用途如下圖所示:




而在上面四個當中,我們經常談論的是右邊那兩個傢伙——stack和heap。今天我們就來聊聊Java代碼在運行的過程中,在stack和heap中到底是什麼樣子的吧。


我們先看下面一段代碼:

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. public static void main(String[] args) {  
  2.     TestReference testReference = new TestReference();  
  3.     int age = 1;  
  4.     Person xiaoqiang = new Person("小強"21);  
  5.     Person xiaoming = new Person("小明"22);  
  6.       
  7.     testReference.selfPlus(age);  
  8.     System.out.println("age經過selfPlus方法的處理後爲:" + age);  
  9.       
  10.     testReference.changeName(xiaoqiang);  
  11.     System.out.println("小強經過changeName方法的處理後的名字爲:" + xiaoqiang.getName());  
  12.       
  13.     testReference.changeAge(xiaoming);  
  14.     System.out.println("小明經過changeAge方法的處理後的年齡爲:" + xiaoming.getAge());  
  15.       
  16. }  
  17.   
  18. public void selfPlus(int i) {  
  19.     i = i + 1;  
  20. }  
  21.   
  22. public void changeName(Person person) {  
  23.     person = new Person("小剛");  
  24. }  
  25.   
  26. public void changeAge(Person person) {  
  27.     person.setAge(25);  
  28. }  


執行完以上代碼,會打印出什麼內容呢?如果你Java基礎還可以,那麼很容易就能知道會輸出什麼內容,想要知道以上代碼會打印什麼內容,需要你明白Java代碼在stack和heap中是怎麼工作的。下面我們結合幾張圖來看看:

[java] view plaincopy在CODE上查看代碼片派生到我的代碼片
  1. int i = 1;  
  2. Person xiaoqiang = new Person("小強"21);  
  3. Person xiaoming = new Person("小明"22);  

當我們執行完上面三行代碼時,內存中的情況如下圖所示:



我們知道stack是用來存放變量的,所以age、xiaoqiang和xiaoming三個變量會被存放到stack裏,而age又是int類型,所以它的值也會被存放在stack裏面。xiaoqiang和xiaoming爲Person類型的引用變量,所以stack只會存放它們的一個引用,也就是對應對象的內存地址,而它們真正的內容被存放在了heap裏面。


當執行到testReference.selfPlus(i);時,selfPlus(int i)方法被調用,此時會在stack中爲形參I開闢一塊內存空間,並將其值設置爲1,此時內存中的情況如下:


因爲調用selfPlus(int i)方法時,將age作爲形參傳遞給該方法,相當於將age的值複製一份給i,所以現在i的值爲1,接着執行i = i + 1;此時i的值被修改爲2,如圖:


此時被修改的只是age的副本,而並非age本身,所以age仍爲1,當selfPlus(int i)方法被執行完,i被銷燬,age不變。接下來看xiaoqiang,當調用changeName(Person person)方法時,會在stack中爲person分配一塊空間,裏面存放的是xiaoqiang指向的地址,如圖:


然後執行到person = new Person("小剛");時,由於又new了一個Person對象,所以在堆中會新建一個person,姓名叫小剛,並且會將person執行小剛的地址,如圖:

此時,person指向的對象由小強變成了小剛,但是xiaoqiang所指向的對象仍然是小強,並沒有發生任何變化。當changeName方法執行完以後,person被銷燬,而小剛也會因爲沒有任何對象對其進行引用,隨後被垃圾回收器回收掉。


下面到了最後一個方法了,當執行testReference.changeAge(xiaoming);時,調用changeAge(Person person)方法,同樣會在stack中爲person分配一塊空間,這次裏面存放的是xiaoming對應的內存地址,如圖:



然後執行person.setAge(25);,此時person指向的對象爲小明,所以在執行setAge方法時,修改的就是heap中小明的屬性值,此時小明的年齡被修改爲25,。方法執行完畢,person被銷燬,內存中最終結果如下:


內存中的最終情況就如上圖所示,當然當main方法執行完以後,之前創建的所有對象都會被銷燬。OK,每天上班做項目的你是不是把一些基礎的東西忘了呢?如果是的話就趕快來補一補吧,好處還是很多的。

【本文轉至】:http://blog.csdn.net/liushuijinger/article/details/41605387

發佈了45 篇原創文章 · 獲贊 27 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章