|
JVM內存分區(JVM運行時數據區)java |
||||
|
全部線程共享的數據區shell (有效範圍:整個進程)數組 |
線程隔離的數據區(線程私有內存)安全 (有效範圍:單個獨立線程)佈局 |
|||
|
方法區spa Method area線程
|
堆(又稱」GC堆」)指針 Heap對象
|
程序計數器blog Program Counter Register |
虛擬機棧 VM Stack
|
本地方法棧 Native Method Stack
|
概述 |
|
|
相似於虛擬機棧
|
||
佔用內存空間大小 |
|
|
較小內存空間 |
和具體的java成員方法代碼有關; 和該線程包含的成員方法個數有關。 |
和具體的Native方法有關 Native方法能夠是其餘語言(如Python、shell) |
服務對象 |
一個進程中的全部線程 (全部線程共享方法區) |
一個進程中的全部線程 全部線程共享Heap區域內存 |
當前線程 (每條線程都有一個獨立的程序計數器,各條線程之間計數器互不影響,獨立存儲) |
當前線程 每一個線程都有本身獨有的該部份內存
|
當前線程 每一個線程都有本身獨有的該部份內存 一個本地方法棧中有多個棧幀 Native method stack=棧幀1+棧幀2+... 每一個棧幀服務於單個的Native方法 |
生命週期 |
|
Jvm啓動時建立 |
其生命週期與當前線程相同 |
其生命週期與當前線程相同 |
其生命週期與當前線程相同 |
存放內容 + 功能 |
v 存放內容: 概述: 方法區用於存儲已經被JVM加載的類信息+常量+靜態變量+即時編譯器編譯後的代碼
詳細解釋:
v 功能: |
v 存放內容: 用於存放對象實例 用於存放全部數組 |
v 存放內容: 指示當前線程將要執行的下一條字節碼指令的行號 v 功能: 做爲當前線程所執行的字節碼的行號指示器,字節碼解釋器工做時經過改變這個計數器的值來選取下一條須要執行的字節碼指令 |
v 存放內容: 虛擬機棧=棧幀1+棧幀2+.... 線程中的每一個java成員方法對應於一個棧幀 棧幀=局部變量表+操做數棧+動態連接+方法出口 局部變量表=8種基本數據類型+對象引用(地址)+returnAddress(一條字節碼指令的地址) 局部變量表是在編譯期間生成的 v 功能: 每一個java成員方法執行過程當中都會建立一個棧幀(stack frame)用於存儲局部變量表、操做數棧、動態連接、方法出口等信息。每個java方法從調用到執行完成的過程,就對應着一個棧幀在虛擬機棧中入棧到出棧的過程。 一個虛擬機棧中有多個棧幀(stack frame), VM Stack=棧幀1+棧幀2+... 每一個棧幀服務於單個的java方法。 |
v 存放內容: v 功能: 每一個Native成員方法執行過程當中都會建立一個棧幀(stack frame)用於存儲局部變量表、操做數棧、動態連接、方法出口等信息。每個Native方法從調用到執行完成的過程,就對應着一個棧幀在本地方法棧棧中入棧到出棧的過程。
|
各個區域存放的數據是如何建立的?
|
|
Step1,JVM遇到一個new指令時, Step2,先去「方法區」的運行時「常量池」中定位到一個類的符號引用, Step3,檢查step2中找到的該類的符號引用所表明的實際的類是否已被加載、解析和初始化過,若是沒有則執行相應的「類的加載過程」 Step4,該類的加載檢查經過以後,JVM纔開始爲該類的新生對象分配內存(在heap內存中分配出一部分給新生對象) 至於具體的內存分配過程,則要看JVM所管理的堆內存空間的連續性是怎樣的:若是堆內存是規整的,則經過「指針碰撞」方法爲新建對象分配內存;若是堆內存是不規整的,只能經過「空閒列表」分配堆內存空間,而且更新「空閒列表」 Step5,由step4可知,從JVM堆內存空間中分配一部分給new出的對象,其分配方法和堆內存空間是否規整有關,而堆內存空間是否規整又和垃圾回收機制有關。若是JVM中的垃圾回收期帶有壓縮整理功能,則堆內存空間是規整的,可使用「指針碰撞」方法分配堆內存空間給new出的對象,不然就只能使用維護「空閒列表」的方法分配堆內存。 Step6,給new出的對象分配好堆內存空間以後,還要對該對象進行必要的設置(即爲對象添加「對象頭」),如該對象是哪一個類的實例、如何才能找到類的元數據信息、對象的哈希碼、對象的GC分代年齡信息等。這些信息存放在對象的對象頭中。 Step7,執行init方法,初始化新建的對象。 Step8,將新生的對象的引用入棧(虛擬機棧)
方法一,爲分配堆內存的操做加上同步處理 方法二,爲單個線程分配獨立的堆內存空間TLAB(本地線程分配緩衝),而後執行每一個線程時,在TLAB上分配內存給new出的對象
|
|
u |
u |
數據在這些區域存儲的佈局是怎樣的?
|
|
對象頭(Header)+實例數據(Instance Data)+對齊填充(padding)
ü 對象自身的運行時數據=哈希碼+GC分代年齡+鎖狀態標誌+線程持有的鎖+偏向線程ID+偏向時間戳 ü 類型指針:這是一個指針,其中存儲了一個地址。這個地址指向JVM內存的「方法區」中的某個部分,「方法區」該部份內容存放的是該對象實例對應的類信息 ü (數組長度)
|
u |
u |
u |
如何使用存放在這些區域的數據? |
u |
使用句柄:堆內存-->句柄池;句柄=對象數據+指向類信息的指針 直接指針:沒有句柄池 |
u |
u |
u |
服務過程當中可能產生的異常 |
OutOfMemoryError:若是方法區中沒有足夠的內存存放相應的類信息或+常量+靜態變量+即時編譯器編譯數據,而且方法區再也沒法擴展時,就會拋出該異常 |
OutOfMemoryError:若是堆中沒有足夠的剩餘內存來存放新的實例對象,而且堆也沒法再擴展時,就會拋出該異常 |
不會產生異常 (這是JVM中惟一一個不會產生OutofMemoryError的區域) |
u StackOverflowError:若是線程請求的棧深度大於JVM所容許的深度,就拋出該異常 u OutOfMemoryError:若是虛擬機棧能夠動態擴展,可是在擴展時沒法申請到足夠的內存,就會拋出該異常 |
u StackOverflowError:若是線程請求的棧深度大於JVM所容許的深度,就拋出該異常 u OutOfMemoryError:若是虛擬機棧能夠動態擴展,可是在擴展時沒法申請到足夠的內存,就會拋出該異常 |