三: JVM的內(nèi)存模型

jdk1.8的內(nèi)存模型主要分為java虛擬機數(shù)據(jù)區(qū)本地內(nèi)存兩大塊
java虛擬機數(shù)據(jù)區(qū)包括:

  • 程序計數(shù)器
  • 本地方法棧
  • java虛擬機棧

本地內(nèi)存包括:

  • 元數(shù)據(jù)區(qū)
  • 直接內(nèi)存

3.1 內(nèi)存模型概覽

3.2 各個區(qū)域介紹

3.2.1 程序計數(shù)器

程序計數(shù)器可以看作當前線程所執(zhí)行的字節(jié)碼的行號指示器。如果線程執(zhí)行的是Java方法那么這個計數(shù)器記錄的是正在執(zhí)行的虛擬機字節(jié)碼指令地址。如果執(zhí)行的是Native方法,這個計數(shù)器為空。(該內(nèi)存區(qū)是唯一沒有規(guī)定任何OutOfMemoryError情況的區(qū)域)

3.2.3 本地方法棧

本地方法棧與虛擬機棧作用相似,它們之間的區(qū)別是虛擬機棧為虛擬機執(zhí)行Java方法服務,而本地方法棧則為虛擬機使用到的Native方法服務。與虛擬機棧一樣本地方法也會拋出StackOverflowError異常和OutOfMemoryError異常。

3.3.3 java堆

  • Java堆通常是Java虛擬機所管理的內(nèi)存中最大的一塊。Java堆是被鎖有線程共享的一塊內(nèi)存區(qū)域,在虛擬機啟動時創(chuàng)建。這塊區(qū)域唯一的目的就是存放對象實例,幾乎所有對象實例都在該區(qū)域分配內(nèi)存。(JIT編譯器的發(fā)展和逃逸分析技術的成熟,棧上分配和標量替換等技術使其不那么絕對。)
  • Java堆時垃圾收集器管理的主要區(qū)域(GC堆),從內(nèi)存回收的角度(收集器一般采用分代收集算法),Java堆還可以細分為:新生代和老年代。新生代再細分有:Eden空間、From Survivor空間、To Survivor空間。
  • 根據(jù)虛擬機規(guī)范,Java堆可以處于物理上的不連續(xù)內(nèi)存中,只要邏輯上是連續(xù)即可。其大小可以通過-Xmx和-Xms控制。如果在堆中沒有內(nèi)存完成實例分配,并且堆也無法擴展時會拋出OutOfMemoryError異常。
  • 需要注意的是在JDK1.7后,字符串常量池從永久代中剝離出來,存放在堆中。

3.3.4 java虛擬機棧

  • Java虛擬機棧跟程序計數(shù)器一樣是線程私有的,它的生命周期和線程相同。虛擬機棧描述的是Java方法執(zhí)行的內(nèi)存模型:每個方法在執(zhí)行時都會創(chuàng)建一個棧幀用于存儲局部變量表、操作數(shù)棧、動態(tài)鏈接、方法出口等信息。每一個方法從調(diào)用到執(zhí)行完成的過程,就對應一個棧幀在虛擬機棧中入棧到出棧的過程。
  • 在虛擬機規(guī)范中,這個區(qū)域規(guī)定了兩種異常狀況:如果線程請求的棧深度大于虛擬機所允許的深度,將拋出StackOverflowError異常,如果虛擬機擴展時無法申請到足夠的內(nèi)存,就會拋出OutOfMemoryError異常。

3.3.5 元數(shù)據(jù)區(qū)

在JDK1.8中元空間區(qū)取代了永久代,永久代原本主要存放Class和Meta的信息。而元空間的本質(zhì)和永久代類似,都是對JVM規(guī)范中方法區(qū)的實現(xiàn)。不過元空間與永久代之間最大的區(qū)別在于:元空間并不在虛擬機中,而是使用本地內(nèi)存。因此,默認情況下,元空間的大小僅受本地內(nèi)存限制。

3.3.6 直接內(nèi)存

直接內(nèi)存不是虛擬機運行時數(shù)據(jù)區(qū)的一部分也不是Java虛擬機規(guī)范中定義的內(nèi)存區(qū)域。在Nio中,它可以使用Native函數(shù)直接分配堆外內(nèi)存,然后通過一個存儲在Java堆中的DirectByteBuffer對象作為這塊內(nèi)存的引用進行操作。(可以提高性能,因為避免了Java堆和Native堆中來回賦值數(shù)據(jù)。)該區(qū)域不受堆大小限制但是會受到本機總內(nèi)存(RAM或SWAP)大小等限制。如果忽略這點將堆大小設置過大使得各個內(nèi)存區(qū)域大小總和大于物理內(nèi)存,它會在動態(tài)擴展時出現(xiàn)OutOfMemoryError異常。

3.4 jdk8的堆內(nèi)存模型

jdk8的堆內(nèi)存模型
  • jdk8的堆內(nèi)存模型由年輕代+老年代組成
  • 年輕代: Eden + 2*Survivor
  • 老年代: OldGen
  • 在jdk1.8中變化最大的Perm區(qū),用Metaspace(元數(shù)據(jù)空間)進行了替換。 需要特別說明的是:Metaspace所占用的內(nèi)存空間不是在虛擬機內(nèi)部,而是在本地內(nèi)存 空間中

3.5 jstat命令查看堆內(nèi)存使用情況

3.5.1 查看class加載統(tǒng)計

jstat -class 進程id

  • Loaded: 加載class數(shù)量
  • Bytes: 加載所用空間大小
  • Unloaded: 未加載數(shù)量
  • Bytes: 未加載空間大小
  • Time: 加載時間

3.5.2 查看編譯統(tǒng)計

jstat -compiler 繼承id

  • Compiled: 編譯數(shù)量
  • Failed: 失敗數(shù)量
  • Invalid: 不可用數(shù)量
  • Time: 編譯花費時間
  • FailedType: 失敗類型
  • FailedMethod: 失敗方法

3.5.3 垃圾回收統(tǒng)計

jstat -gc 進程id

  • S0C:第一個Survivor區(qū)的大?。↘B)
  • S1C:第二個Survivor區(qū)的大?。↘B)
  • S0U:第一個Survivor區(qū)的使用大小(KB)
  • S1U:第二個Survivor區(qū)的使用大?。↘B)
  • EC:Eden區(qū)的大?。↘B)
  • EU:Eden區(qū)的使用大?。↘B)
  • OC:Old區(qū)大?。↘B)
  • OU:Old使用大?。↘B)
  • MC:方法區(qū)大?。↘B)
  • MU:方法區(qū)使用大小(KB)
  • CCSC:壓縮類空間大?。↘B)
  • CCSU:壓縮類空間使用大?。↘B)
  • YGC:年輕代垃圾回收次數(shù)
  • YGCT:年輕代垃圾回收消耗時間
  • FGC:老年代垃圾回收次數(shù)
  • FGCT:老年代垃圾回收消耗時間
  • GCT:垃圾回收消耗總時間
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容