Java內存管理

jopen 10年前發布 | 15K 次閱讀 Java內存 Java開發

首先我們要明白一點,我們所使用的變量就是一塊一塊的內存空間!!

一、內存管理原理:


在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數據類型

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; 

這是 基本數據類型 變量,具體的值就存放在棧中,并沒有只指針的概念!

下圖就是本例的內存布置圖:

Java內存管理

此外我們還要知道Student zhouxingxing = new Student(); 包括了聲明和創建,即:Student zhouxingxing;和zhouxingxing = new Student();其中聲明只是在棧中聲明一個空間,但還沒有具體的值,聲明后的情況如下圖所示:

Java內存管理

創建后的情況如下圖所示:

Java內存管理

(4)引用類型中的數組也封裝了指針,即便是基本數據類型的數組也封裝了指針,數組也是引用類型。比如代碼int[] arr = new int[]{23,2,4,3,1};如下圖所示:

Java內存管理

 

 五、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";這行代碼運行

完,如下圖:

Java內存管理

 當調用方法時testString.change(name),內存變化為:

Java內存管理

在方法體內,參數str賦予一個新值,str = "旺旺老師"。因為String是定長,系統就會在堆中分配一塊新的內存空間37DF,這樣str指向了新的內存空間37DF,而name還是指向36DF, 37DF的改變對它已沒影響:

Java內存管理

最后,方法調用結束,str與37DF的內存空間消亡。Name的值依然為wangwang,并沒有改變。

所以String雖然是引用類型參數,但值依然不變:

Java內存管理

 

 (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 

分析:

Java內存管理

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!