Java虛擬機在執行Java程式的程序中會把它所管理的記憶體劃分為若干個不同的資料區域,


1 方法區
簡單說方法區用來存盤型別的元資料資訊,一個.class檔案是類被java虛擬機使用之前的表現形式,一旦這個類要被使用,java虛擬機就會對其進行裝載、連接(驗證、準備、決議)和初始化,而裝載后的結果就是由.class檔案轉變為方法區中的一段特定的資料結構,
(1)方法區存盤的資訊
型別資訊:全限定名、直接超類的全限定名、類的型別還是介面型別、訪問修飾符、直接超介面的全限定名的有序串列
欄位資訊:欄位名、欄位型別、欄位的修飾符
方法資訊:方法名、方法回傳型別、方法引數的數量和型別(按照順序)、方法的修飾符
其他資訊:除了常量以外的所有類(靜態)變數、一個指向ClassLoader的指標、一個指向Class物件的指標、常量池(常量資料以及對其他型別的符號參考)
(2)永久代、元空間
方法區是java中的接?,永久代、元空間是具體實作類,
永久代,以前的方法區的實作,jdk8以后元空間代替了存在堆區,
元空間,1.8及以后方法區的實作,直接記憶體、OS記憶體,
(3)常量池
Java中的常量池,實際上分為兩種形態:靜態常量池和運行時常量池,
所謂靜態常量池,即*.class檔案中的常量池,class檔案中的常量池不僅僅包含字串(數字)字面量,還包含類、方法的資訊,占用class檔案絕大部分空間,
運行時常量池,則是jvm虛擬機在完成類裝載操作后,將class檔案中的常量池載入到記憶體中,并保存在方法區中,我們常說的常量池,就是指方法區中的運行時常量池,
2 本地方法堆疊
本地方法堆疊和java虛擬機堆疊差不多,唯一的區別是,java虛擬機堆疊為java虛擬機執行java服務,本地方法堆疊為虛擬機執行本地方法服務,也可以理解為 java調?c、c++的元件,運???的函式需要的堆疊,
3 程式計數器
程式計數器(Program Counter Register)是一塊較小的記憶體空間,它的作用可以看做是當前執行緒所執行的位元組碼的行號指示器,在虛擬機的概念模型里(僅是概念模型,各種虛擬機可能會通過一些更高效的方式去實作),位元組碼解釋器作業時就是通過改變這個計數器的值來選取下一條需要執行的位元組碼指令,分支、回圈、跳轉、例外處理、執行緒恢復等基礎功能都需要依賴這個計數器來完成,
由于Java虛擬機的多執行緒是通過執行緒輪流切換并分配處理器執行時間的方式來實作的,在任何一個確定的時刻,一個處理器(對于多核處理器來說是一個內核)只會執行一條執行緒中的指令,因此,為了執行緒切換后能恢復到正確的執行位置,每條執行緒都需要有一個獨立的程式計數器,各條執行緒之間的計數器互不影響,獨立存盤,我們稱這類記憶體區域為“執行緒私有”的記憶體,
4 虛擬機堆疊
Java虛擬機堆疊(Java Virtual Machine Stacks)也是執行緒私有的,它的生命周期與執行緒相同,虛擬機堆疊描述的是Java方法執行的記憶體模型:每個方法被執行的時候都會同時創建一個堆疊幀(Stack Frame)用于存盤區域變數表、操作堆疊、動態鏈接、方法出口等資訊,每一個方法被呼叫直至執行完成的程序,就對應著一個堆疊幀在虛擬機堆疊中從入堆疊到出堆疊的程序,

4.1 動態連接
虛擬機運行的時候,運行時常量池會保存大量的符號參考,這些符號參考可以看成是每個方法的間接參考,如果代表堆疊幀A的方法想呼叫代表堆疊幀B的方法,那么這個虛擬機的方法呼叫指令就會以B方法的符號參考作為引數,但是因為符號參考并不是直接指向代表B方法的記憶體位置,所以在呼叫之前還必須要將符號參考轉換為直接參考,然后通過直接參考才可以訪問到真正的方法,
如果符號參考是在類加載階段或者第一次使用的時候轉化為直接應用,那么這種轉換成為靜態決議,如果是在運行期間轉換為直接參考,那么這種轉換就成為動態連接,
4.2 區域變數表
區域變數表是一組變數值存盤空間,用于存放方法引數和方法內部定義的區域變數,
4.3 運算元堆疊
運算元堆疊 和區域變數區一樣,運算元堆疊也是被組織成一個以字長為單位的陣列,但是和前者不同的是,它不是通過索引來訪問,而是通過標準的堆疊操作——壓堆疊和出堆疊—來訪問的,比如,如果某個指令把一個值壓入到運算元堆疊中,稍后另一個指令就可以彈出這個值來使用,
4.4 回傳地址
方法的回傳分為兩種情況,不過無論是那種方式的方法結束,在退出當前方法時都會跳轉到當前方法被呼叫的位置,
(1)一種是正常退出,退出后會根據方法的定義來決定是否要傳回傳值給上層的呼叫者,
(2)一種是例外導致的方法結束,這種情況是不會傳回傳值給上層的呼叫方法,
5 堆
對于大多數應用來說,Java堆(Java Heap)是Java虛擬機所管理的記憶體中最大的一塊,Java堆是被所有執行緒共享的一塊記憶體區域,在虛擬機啟動時創建,此記憶體區域的唯一目的就是存放物件實體,幾乎所有的物件實體都在這里分配記憶體,

堆大小 = 新生代 + 老年代,其中,堆的大小可以通過引數 –Xms、-Xmx 來指定,
新生代如何進入老年代
(1) 大物件直接進入年老代
物件大小超過Eden區的一半直接進入年老代,
(2) 長期存活的物件將進入年老代
虛擬機給每個物件定義了一個物件年齡計數器,在物件在Eden創建并經過第一次Minor GC后仍然存活,并能被Suivivor容納的話,將會被移動到Survivor空間,并物件年齡設定為1,每經歷過Minor GC,年齡就增加1歲,當到一定程度(默認15歲,可以通過引數-XXMaxTenuringThreshold設定),就將會晉升年老代,
(3) 動態物件年齡判定
了更好地適應不同程式記憶體狀況,虛擬機并不硬性要求物件年齡達到MaxTenuringThreshold才能晉升老年代,如果在Survivor空間中相同年齡所有物件大小的總和大于Survivor空間的一半,年齡大于或等于該年齡的物件就可以直接進入年老代,
(4)空間分配擔保
當Eden和一個Survivor區中依然存活的物件無法放入到Survivor中,則通過分配擔保機制提前轉移到老年代中,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/262908.html
標籤:java
上一篇:Java開發的環境搭建
下一篇:查詢支付寶電話號中隱藏的六位數
