JAVA記憶體管理 [轉]

xusir發表於2014-09-17

首先我們要明白一點,我們所使用的變數就是一塊一塊的記憶體空間!!

 
一、記憶體管理原理:
 
在java中,有java程式、虛擬機器、作業系統三個層次,其中java程式與虛擬機器互動,而虛擬機器與作業系統間互動!這就保證了java程式的平臺無關性!下面我們從程式執行前,程式執行中、程式執行記憶體溢位三個階段來說一下記憶體管理原理!
 
1、程式執行前:JVM向作業系統請求一定的記憶體空間,稱為初始記憶體空間!程式執行過程中所需的記憶體都是由java虛擬機器從這片記憶體空間中劃分的。
 
2、程式執行中:java程式一直向java虛擬機器申請記憶體,當程式所需要的記憶體空間超出初始記憶體空間時,java虛擬機器會再次向作業系統申請更多的記憶體供程式使用!
 
3、記憶體溢位:程式接著執行,當java虛擬機器已申請的記憶體達到了規定的最大記憶體空間,但程式還需要更多的記憶體,這時會出現記憶體溢位的錯誤!

至此可以看出,Java 程式所使用的記憶體是由 Java 虛擬機器進行管理、分配的。Java 虛擬機器規定了 Java 程式的初始記憶體空間和最大記憶體空間,開發者只需要關心 Java 虛擬機器是如何管理記憶體空間的,而不用關心某一種作業系統是如何管理記憶體的。  
 
二、 RUNTIME 類的使用:
 
Java 給我們提供了Runtime 類得到JVM 記憶體的資訊
 方法名稱  引數 作用  返回值 
 getRuntime   無  獲取Runtime 物件   Runtime 物件 
 totalMemory   無  獲取JVM 分配給程式的記憶體數量   long:記憶體數量 
 freeMemory  無  獲取當前可用的記憶體數量   long:記憶體數量 
 maxMemory   無  獲取JVM 可以申請到的最大記憶體數量  long:記憶體數量 
   
 
三、記憶體空間邏輯劃分:
 
JVM 會把申請的記憶體從邏輯上劃分為三個區域,即:方法區、堆與棧。 
 
方法區:方法區預設最大容量為64M,Java虛擬機器會將載入的java類存入方法區,儲存類的結構(屬性與方法),類靜態成員等內容。
 
堆:預設最大容量為64M,堆存放物件持有的資料,同時保持對原類的引用。可以簡單的理解為物件屬性的值儲存在堆中,物件呼叫的方法儲存在方法區。
 
棧:棧預設最大容量為1M,在程式執行時,每當遇到方法呼叫時,Java虛擬機器就會在棧中劃分一塊記憶體稱為棧幀(Stack frame),棧幀中的記憶體供區域性變數(包括基本型別與引用型別)使用,當方法呼叫結束後,Java虛擬機器會收回此棧幀佔用的記憶體。 
四、java資料型別
1、基本資料型別:沒封裝指標的變數。
宣告此型別變數,只會在棧中分配一塊記憶體空間。
 
2、引用型別:就是底層封裝指標的資料型別。
他們在記憶體中分配兩塊空間,第一塊記憶體分配在棧中,只存放別的記憶體地址,不存放具體數值,我們也把它叫指標型別的變數,第二塊記憶體分配在堆中,存放的是具體數值,如物件屬性值等。
 
3、下面我們從一個例子來看一看:
public class Student { 
  String stuId; 
  String stuName; 
  int stuAge; 
} 
 
public class TestStudent { 
  public static void main(String[] args) { 
    Student zhouxingxing = new Student(); 
    String name = new String("旺旺");  
    int a = 10; 
    char b = 'm'; 
    zhouxingxing.stuId = "9527"; 
    zhouxingxing.stuName = "周星星"; 
    zhouxingxing.stuAge = 25; 
  } 
}

 

 
(1)類當然是存放在方法區裡面的。
 
(2)Student zhouxingxing = new Student(); 
這行程式碼就建立了兩塊記憶體空間,第一個在棧中,名字叫zhouxingxing,它就相當於指標型別的變數,我們看到它並不存放學生的姓名、年齡等具體的數值,而是存放堆中第二塊記憶體的地址,第二塊才存放具體的數值,如學生的編號、姓名、年齡等資訊。
 
(3)int a = 10; 
這是 基本資料型別 變數,具體的值就存放在棧中,並沒有只指標的概念!
 
下圖就是本例的記憶體佈置圖:
此外我們還要知道Student zhouxingxing = new Student(); 包括了宣告和建立,即:Student zhouxingxing;和zhouxingxing = new Student();其中宣告只是在棧中宣告一個空間,但還沒有具體的值,宣告後的情況如下圖所示:
建立後的情況如下圖所示:
(4)引用型別中的陣列也封裝了指標,即便是基本資料型別的陣列也封裝了指標,陣列也是引用型別。比如程式碼int[] arr = new int[]{23,2,4,3,1};如下圖所示:
 五、java值傳參與引用引數
 
(1)引數根據呼叫後的效果不同,即是否改變引數的原始數值,又可以分為兩種:按值傳遞的引數與按引用傳遞的引數。
按值傳遞的引數原始數值不改變,按引用傳遞的引數原始數值改變!這是為什麼呢?其實相當簡單:
我們知道基本資料型別的變數存放在棧裡面,變數名處存放的就是變數的值,那麼當基本資料型別的變數作為引數時,傳遞的就是這個值,只是把變數的值傳遞了過去,不管對這個值如何操作,都不會改變變數的原始值。而對引用資料型別的變數來說,變數名處存放的地址,所以引用資料型別的變數作為傳參時,傳遞的實際上是地址,對地址處的內容進行操作,當然會改變變數的值了!
 
(2)特例:string
 
public class TestString { 
  public static void main(String[] args) { 
     
    String name = "wangwang"; 
    TestString testString = new TestString(); 
     
    System.out.println("方法呼叫前:" + name); 
    testString.change(name); 
    System.out.println("方法呼叫後:" + name); 
  } 
   
  void change(String str) { 
    str = "旺旺老師"; 
    System.out.println("方法體內修改值後:" + str); 
  } 
} 

 

 
結果:
方法呼叫前:wangwang 
方法體內修改值後:旺旺老師 
方法呼叫後:wangwang 
 
分析:
上例中,雖然引數String 是引用資料型別,但其值沒有發生改變,這是因為String 類
是final 的,它是定長,我們看初始情況,即String name = "wangwang";這行程式碼執行
完,如下圖:
當呼叫方法時testString.change(name),記憶體變化為:
在方法體內,引數str賦予一個新值,str = "旺旺老師"。因為String是定長,系統就會在堆中分配一塊新的記憶體空間37DF,這樣str指向了新的記憶體空間37DF,而name還是指向36DF, 37DF的改變對它已沒影響:
最後,方法呼叫結束,str與37DF的記憶體空間消亡。Name的值依然為wangwang,並沒有改變。
所以String雖然是引用型別引數,但值依然不變:
 
 (3)無法交換的例子:
 
public class TestChange { 
  void change(Student stu1, Student stu2) { 
    stu1.stuAge ++; 
    stu2.stuAge ++; 
    Student stu = stu1; 
    stu1 = stu2; 
    stu2 = stu; 
  } 
   
  public static void main(String[] args) { 
     
    Student furong = new Student(); 
    furong.stuName = "芙蓉姐姐"; 
    furong.stuAge = 30; 
     
    Student fengjie = new Student(); 
    fengjie.stuName = "鳳姐"; 
    fengjie.stuAge = 26; 
     
    TestChange testChange = new TestChange(); 
    testChange.change(furong, fengjie); 
     
    System.out.println(furong.stuName); 
    System.out.println(furong.stuAge); 
     
    System.out.println(fengjie.stuName); 
    System.out.println(fengjie.stuAge); 
  } 
 
} 

  

 
執行結果:
芙蓉姐姐 
31 
鳳姐 
27 
 
分析:
 
 

相關文章