1. 程式人生 > >Java內存管理的進一步理解-模擬過程圖解

Java內存管理的進一步理解-模擬過程圖解

pri java棧 中間 nta 源代碼 超過 size mar 分享圖片

Java內存管理的進一步理解-模擬過程圖解--轉載

java的內存管理分為:

1、堆內存;2、棧內存;3、方法區;4、本地方法區

/* 1:方法區 方法區存放裝載的類數據信息包括: (1):基本信息: 1)每個類的全限定名 2)每個類的直接超類的全限定名(可約束類型轉換) 3)該類是類還是接口 4)該類型的訪問修飾符 5)直接超接口的全限定名的有序列表 (2):每個已裝載類的詳細信息: 1)運行時常量池: 存放該類型所用的一切常量(直接常量和對其它類型、字段、方法的符號引用),它們以數組形式通過索引被訪問,是外部調用與類聯系及類型對象化的橋梁。它是類文件(字節碼)常量池的運行時表示。(還有一種靜態常量池,在字節碼文件中)。
2)字段信息: 類中聲明的每一個字段的信息(名,類型,修飾符)。 3)方法信息: 類中聲明的每一個方法的信息(名,返回類型,參數類型,修飾符,方法的字節碼和異常表)。 4)靜態變量 5)到類 classloader 的引用:即到該類的類裝載器的引用。 6)到類 class 的引用: 虛擬機為每一個被裝載的類型創建一個 class 實例, 用來代表這個被裝載的類。 2:棧內存 Java棧內存以幀的形式存放本地方法的調用狀態(包括方法調用的參數,局部變量,中間結果等)。每調用一個方法就將對應該方法的方法幀壓入 Java 棧,成為當前方法幀。當調用結束(返回)時,就彈出該幀。
編譯器將源代碼編譯成字節碼(.class)時, 就已經將各種類型的方法的局部變量, 操作數棧大小確定並放在字節碼中,隨著類一並裝載入方法區。當調用方法時,通過訪問方法區中的類的信息,得到局部變量以及操作數棧的大小。 也就是說: 在方法中定義的一些基本類型的變量和對象的引用變量都在方法的棧內存中分配。 當在一段代碼塊定義一個變量時,Java 就在棧中為這個變量分配內存空間,當超過變量的作用域後,Java 會自動釋放掉為該變量所分配的內存空間, 該內存空間可以立即被另作它用。 棧內存的構成: Java 棧內存由局部變量區、操作數棧、幀數據區組成。 (1):局部變量區為一個以字為單位的數組,每個數組元素對應一個局部變量的值。調用方法時,將方法的局部變量組成一個數組,通過索引來訪問。若為非靜態方法,則加入一個隱含的引用參數 this,該參數指向調用這個方法的對象。而靜態方法則沒有this參數。因此,在靜態方法裏無法訪問對象信息。
(2):操作數棧也是一個數組,但是通過棧操作來訪問。所謂操作數是那些被指令操 作的數據。當需要對參數操作時如 a=b+c,就將即將被操作的參數壓棧,如將 b 和 c 壓棧, 然後由操作指令將它們彈出,並執行操作。虛擬機將操作數棧作為工作區。 (3):幀數據區處理常量池解析,異常處理等 3:堆內存 堆內存用來存放由 new 創建的對象和數組。在堆中分配的內存,由 Java 虛擬機的自動垃圾回收器來管理。 在堆中產生了一個數組或對象後,還可以在棧中定義一個特殊的變量, 讓棧中這個變量的取值等於數組或對象在堆內存中的首地址,棧中的這個變量就成了數組或對象的引用變量。
引用變量就相當於是為數組或對象起的一個名稱, 以後就可以在程序中使用棧中的引用變量來訪問堆中的數組或對象。
4:本地方法棧內存 與調用的本地方法的語言相關,如:調用的是一個c語言方法則為一個c棧。本地方法可以回調java方法。若有java方法調用本地方法,虛擬機就運行這個本地方法。 在虛擬機看來運行這個本地方法就是執行這個java方法,如果本地方法拋出異常,虛擬機就認為是這個java方法拋出異常。 Java通過Java本地接口JNI(Java Native Interface)來調用其它語言編寫的程序,在Java裏面用native修飾符來描述一個方法是本地方法。 */

下面通過一個簡單的代碼示例,理解Java中,內存是怎麽進行分配與管理的。示例如下:

public class JavaRamExplain {  
    public static void main(String[] args) {  
        Person.whatCountry();  
          
        Person sam = new Person("sam", 20);  
        sam.introduceSelf();  
    }  
}  
class Person {  
  
    private String name;  
    private int age;  
    public static String country = "china";  
  
    public Person(String name, int age) {  
        this.name = name;  
        this.age = age;  
    }  
  
    public void introduceSelf() {  
        System.out.println("My name‘s " + name + ",i‘m " + age + " years old.");  
    }  
  
    public static void whatCountry() {  
        System.out.println("This people come from " + country);  
    }  
} 

當開始運行JavaRamExplain類時,JVM便會開始進行內存的分配管理工作。

圖解過程為:

技術分享圖片

(圖片較大,看不清可以圖片右鍵-查看圖像,進行查看原圖)

可以看到到第八步工作結束後:

棧內存中的數據全部被釋放(所以說棧內存中的數據的生命周期是已知並固定的,因為隨著方法的執行結束,棧內存便會進行釋放);

堆內存中的Person對象,現已沒有任何對象引用指向它,所以它將被視作內存中的“垃圾”,等待回收。(堆內存中的數據由java的垃圾回收機制自動進行處理,所以其生命周期不確定)

由圖中也可以看到:

類的方法會進行壓棧和彈棧,對應的,方法中用到的參數(變量)便會相應的在棧內存中進行存儲和釋放。所以棧內存用於存放局部變量(包括基本類型和引用類型)。

類的對象會被存放到堆內存中,相應的該對象所包含的成員變量也會被存放到該空間。

類本身將在jvm通過.class運行該類時就會被加載到內存中的方法區內,顧名思義,方法區用於保存類的方法代碼,其中普通方法被存放在非靜態區,靜態成員(方法和變量)被存放在方法區中專門的靜態區當中。

棧內存是方法的運行區域(因為方法中定義的局部變量需要在棧裏開辟空間),方法區是方法的存放區域。

Java內存管理的進一步理解-模擬過程圖解