轉載: Java虛擬機:運行時內存數據區域、對象內存分配與訪問

轉載:  https://blog.csdn.net/a745233700/article/details/80291694  (雖然大部份內容都實際上是深刻理解jvm虛擬機這本書裏的,不過整理的很牛逼)java

一 java運行時內存中的數據區域   

每個Java程序啓動後,會得到一個JVM的實例,用來管理內存。Java 虛擬機在執行Java程序的過程當中會把它所管理的內存劃分爲若干個不一樣的數據區域。這些區域都有個字的用途,以及建立和銷燬時間。Java虛擬機所管理的內存將會包括如下幾個運行時數據區域:程序員

 

 

一、程序計數器:程序計數器是一塊較小的空間,是當前線程執行的字節碼的行號指示器,字節碼解釋器工做時,就是經過改變計數器的值來選取下一條須要執行的字節碼指令。(線程私有,每一個線程都有一個獨立的程序計數器,互不影響,獨立存儲)數組

二、Java虛擬機棧:線程私有,生命週期與線程的生命週期相同。它描述java方法執行的內存模型,每一個方法執行的時候都會建立一個棧幀,以幀的形式存放本地方法的調用狀態,用於存儲局部變量表、操做數棧、動態連接、方法出口等信息。每一個方法從調用到執行完成,就對應着一個棧幀在虛擬機中入棧到出棧的過程。jvm

 

 

三、本地方法棧:本地方法棧的做用和虛擬機棧的做用很是類似,區別是虛擬機棧爲虛擬機執行java方法服務,而本地方法棧則爲虛擬機使用到的Native方法服務。佈局

四、Java堆:佔用內存最大的區域,在虛擬機啓動時建立,用於存放對象實例,能夠劃分爲新生代和老年代。spa

五、方法區:用於存儲被虛擬機加載的類信息,常量,靜態變量,即便編譯器編譯後的代碼等數據。.net

 

 二 內存分配:       

首先將class文件加載到方法區(存放類的基本信息,靜態變量,編譯後的代碼等信息),而後new一個類,爲這個類在Java堆中分配內存(主要是給字段屬性分配內存)。調用一個方法時,根據方法的引用在方法區找到對應方法,而後在Java虛擬機棧中分配一個棧幀給這個方法存儲相關信息。線程

一、new對象建立的過程:3d

(1)首先將去檢查這個指令的參數是否能在常量池中定位到一個類的符號引用;指針

(2)檢查這個符號引用表明的類是否已被加載、解析和初始化;

(3)若是沒有,那必須先執行相應的類加載過程;

(4)若是有,虛擬機將爲新生對象分配內存,並使用CAS保證操做原子性,分配方式有:指針碰撞和空閒列表;

(5)虛擬機將分配到的內存空間都初始化爲零值,這一步保證了對象的實例字段在Java代碼中能夠不賦初始值就能夠直接使用;

(6)對對象進行必要的設置;

(7)執行<init>方法,把對象按照程序員意願進行初始化。

二、分配方式:

(1)指針碰撞:若是java堆是絕對規整的,全部用過的內存都放在一邊,全部沒用過的內存存放在另外一邊,中間存放一個指針做爲分界點指示器。分配內存時,將指針從用過的內存區域向空閒內存區域移動等距離區域。

(2)空閒列表:若是java不是規整的,這時,虛擬機就必須維護一張列表,列表上記錄了可用的內存塊,在分配內存時,從列表上找到一個足夠大的連續內存塊分配給對象,並更新列表上的記錄。

三、對象的內存佈局:

在HotSpot中,對象的內存佈局分紅三部分:對象頭,實例數據,對齊填充。

(1)對象頭:包括兩部分的信息:

        第一部分用於存儲對象自身的運行時數據,如哈希碼,GC代年齡,鎖狀態標誌等。

        第二部分是對象指向它的類元數據的類元指針,虛擬機經過這個指針來肯定這個對象是哪一個類的實例。若是對象是一個Java數組,那對象頭中還必須有一塊用於記錄數組長度的數據。

(2)實例數據:是對象真正存儲的有效信息,是在程序代碼中所定義的各類類型的字段內容,相同寬度的字段會被分配到一塊兒。

(3)對齊填充:並非必然存在的,僅起着佔位符的做用。

四、對象的訪問定位:

    Java程序經過棧上的reference數據來操做堆上的具體對象。目前訪問對象主要有兩種方式:經過句柄訪問對象和直接指針訪問對象。

(1)經過句柄訪問對象:

 

 

(2)經過直接指針訪問對象:

 

 

(3)優劣對比:

   ① 使用句柄,reference中存儲的是穩定的句柄地址,在對象被移動時只會改變句柄中的實例數據指針,而reference自己不須要修改。

    ②直接指針,速度快,節省一次指定定位的開銷。

相關文章
相關標籤/搜索