【Java】記憶體分析
阿新 • • 發佈:2019-02-05
程式與記憶體
程式要想執行,一般需要以下三個步驟,如圖1-1所示:
1、將程式載入到記憶體區。
2、作業系統程式碼找到程式的main方法開始執行。
3、執行過程中進行記憶體管理。
圖1-1 程式執行過程
一個程式的記憶體分析
比如我們寫了一個求空間中兩點之間距離的程式。很簡單,只要一個點物件就可以完成了。程式碼如下:
class Point {
double x, y, z;
Point(double _x, double _y, double _z) {
x = _x;
y = _y;
z = _z;
}
void setX(double _x) {
x = _x;
}
double getDistance(Point p) {
return (x - p.x)*(x - p.x) + (y - p.y)*(y - p.y) + (z - p.z)*(z - p.z);
}
}
同樣,也需要一個類來使用Point類,我們將這個使用過程寫在了main函式中,程式碼如下:
public class TestPoint {
public static void main(String[] args) {
Point p = new Point(1.0 , 2.0, 3.0);
Point p1 = new Point(0.0, 0.0, 0.0);
//計算點p到原點的距離
System.out.println(p.getDistance(p1));
//設定點的x座標為5
p.setX(5.0);
//計算點p到點(1.0,1.0,1.0)的距離
System.out.println(p.getDistance(new Point(1.0, 1.0, 1.0)));
}
}
我們開始看第一句程式碼:Point p = new Point(1.0, 2.0, 3.0);
new Point(1.0, 2.0, 3.0)
的過程其實就是在堆記憶體中新建了一個Point物件,裡面有三個成員變數(x = 1.0 ,y = 2.0 ,z = 3.0)。然後再執行宣告和賦值,Point p
即Point物件的宣告過程,在記憶體的棧空間中分配一塊兒記憶體,通過名字p呼叫,為其賦值的過程即:將堆中new出來的物件的引用儲存到這塊棧空間中。記憶體狀態如圖2-1所示: 圖2-1 第一句程式碼執行完成後記憶體圖
第二句程式碼的分析過程同一類似,不再贅述,執行完成後記憶體空間狀態如圖2-2所示:
圖2-2 第二句程式碼執行完成後記憶體圖
第三句程式碼:
System.out.println(p.getDistance(p1))
,其中println是字串的列印輸出方法,而括號中是點物件方法的呼叫,它們的過程是一樣的,那我們直接分析括號中的方法呼叫過程,即:p.getDistance(p1)。 我們可以看到
getDistance(Point p)
方法中有一個引數Point p,p也叫區域性變數。當我們呼叫這個方法的時候,在棧記憶體中會分配一直臨時變數p,指向p1的引用物件。計算完成後,會有一個返回值,記憶體中的棧空間會分配一塊兒空間來儲存這個返回值。這時方法呼叫完畢,為其區域性變數分配的記憶體空間收回,即區域性變數p消失。當System.out.println()執行完畢,將返回值列印在介面上,為返回值分配的記憶體消失。所以第三句程式碼執行完成之後,記憶體空間無變化。(它曾經來過,它現在沒了) 第四句程式碼:
p.setX(5.0);
,呼叫setX()方法將p引用的物件的x值修改為5.0,此時記憶體空間狀態如圖2-3所示: 圖2-3 第三句程式碼執行完成後記憶體圖
最後一句程式碼:
System.out.println(p.getDistance(new Point(1.0, 1.0, 1.0)));
。遇到稍複雜的表示式,我們應從裡向外分析。new Point(1.0, 1.0, 1.0)
也就是在堆中新建一個點物件,裡面有三個成員變數(x=1.0 , y=1.0 ,z=1.0)。然後呼叫物件p的getDistance()
方法,新建一個臨時變數p(引數),指向剛new出來的這物件,計算結果,返回並列印計算結果,方法執行完畢,為區域性變數p和返回值分配的記憶體空間消失。堆中的點物件(1.0,1.0,1.0)沒有引用指向它,等待垃圾收集器回收。此時記憶體空間狀態如圖2-4所示: 圖2-4 最後一句程式碼執行完成後記憶體圖
main方法執行完成後,區域性變數p和p1也就消失了,其引用的物件等待垃圾收集器回收。
總結
- 基本資料型別只在棧中分配一塊空間。
- 引用型別在棧中和堆中各有一塊記憶體空間。
- 方法執行完畢,為其分配的區域性變數消失,棧中的返回值如果沒有用到也會默默的消失。
- 垃圾收集器判斷一個物件是否需要回收的標準是:有沒有引用指向它。如果沒有,則回收。
- 字串常量在DataSegment和棧中分配記憶體空間,相同字串常量的引用相同(java優化機制)。
- 字串變數在堆疊中分配記憶體,相同字串的引用不同,並重寫了equals()方法,以方便比較字串內容是否一致。