Hotspot的Metaspace

Meta Space是JDK1.8引入的,在JDK1.8使用的是方法區,永久代(Permnament Generation)。
元空間存儲的是元信息,使用的是操做系統的本地內存(Metaspace與PermGen之間最大的區別),能夠是不連續的,由元空間虛擬機進行管理。能夠產生OutOfMemoryError
html

一、元空間的特色

  • 充分利用了Java語言規範中的好處:類及相關的元數據的生命週期與類加載器的一致。
  • 每一個加載器有專門的存儲空間
  • 只進行線性分配
  • 不會單獨回收某個類
  • 省掉了GC掃描及壓縮的時間
  • 元空間裏的對象的位置是固定的
  • 若是GC發現某個類加載器再也不存活了,會把相關的空間整個回收掉

二、元空間的內存分配模型

  • 絕大多數的類元數據的空間都從本地內存中分配
  • 用來描述類元數據的類(klasses)也被刪除了
  • 分元數據分配了多個虛擬內存空間
  • 給每一個類加載器分配一個內存塊的列表。塊的大小取決於類加載器的類型; sun/反射/代理對應的類加載器的塊會小一些
  • 歸還內存塊,釋放內存塊列表
  • 一旦元空間的數據被清空了,虛擬內存的空間會被回收掉
  • 減小碎片的策略

咱們來看下JVM是如何給元數據分配虛擬內存的空間的 java

你能夠看到虛擬內存空間是如何分配的(vs1,vs2,vs3) ,以及類加載器的內存塊是如何分配的。CL是Class Loader的縮寫。面試

理解_mark和_klass指針

要想理解下面這張圖,你得搞清楚這些指針都是什麼東西。oop

JVM中,每一個對象都有一個指向它自身類的指針,不過這個指針只是指向具體的實現類,而不是接口或者抽象類。佈局

對於32位的JVM:性能

_mark : 4字節常量spa

_klass: 指向類的4字節指針 對象的內存佈局中的第二個字段( _klass,在32位JVM中,相對對象在內存中的位置的偏移量是4,64位的是8)指向的是內存中對象的類定義。操作系統

64位的JVM:代理

_mark : 8字節常量指針

_klass: 指向類的8字節的指針

開啓了指針壓縮的64位JVM: _mark : 8字節常量

_klass: 指向類的4字節的指針

Java對象的內存佈局

類指針壓縮空間(Compressed Class Pointer Space)

只有是64位平臺上啓用了類指針壓縮纔會存在這個區域。對於64位平臺,爲了壓縮JVM對象中的_klass指針的大小,引入了類指針壓縮空間(Compressed Class Pointer Space)。

壓縮指針後的內存佈局

指針壓縮概要

  • 64位平臺上默認打開
  • 使用-XX:+UseCompressedOops壓縮對象指針 "oops"指的是普通對象指針("ordinary" object pointers)。 Java堆中對象指針會被壓縮成32位。 使用堆基地址(若是堆在低26G內存中的話,基地址爲0)

  • 使用-XX:+UseCompressedClassPointers選項來壓縮類指針

  • 對象中指向類元數據的指針會被壓縮成32位

  • 類指針壓縮空間會有一個基地址

元空間和類指針壓縮空間的區別

  • 類指針壓縮空間只包含類的元數據,好比InstanceKlass, ArrayKlass 僅當打開了UseCompressedClassPointers選項才生效 爲了提升性能,Java中的虛方法表也存放到這裏 這裏到底存放哪些元數據的類型,目前仍在減小

  • 元空間包含類的其它比較大的元數據,好比方法,字節碼,常量池等。

三、元空間內存管理

元空間的內存管理由元空間虛擬機來完成。先前,對於類的元數據咱們須要不一樣的垃圾回收器進行處理,如今只須要執行元空間虛擬機的C++代碼便可完成。在元空間中,類和其元數據的生命週期和其對應的類加載器是相同的。話句話說,只要類加載器存活,其加載的類的元數據也是存活的,於是不會被回收掉。 
準確的來講,每個類加載器的存儲區域都稱做一個元空間,全部的元空間合在一塊兒就是咱們一直說的元空間。當一個類加載器被垃圾回收器標記爲再也不存活,其對應的元空間會被回收。在元空間的回收過程當中沒有重定位和壓縮等操做。可是元空間內的元數據會進行掃描來肯定Java引用。 
元空間虛擬機負責元空間的分配,其採用的形式爲組塊分配。組塊的大小因類加載器的類型而異。在元空間虛擬機中存在一個全局的空閒組塊列表。當一個類加載器須要組塊時,它就會從這個全局的組塊列表中獲取並維持一個本身的組塊列表。當一個類加載器再也不存活,那麼其持有的組塊將會被釋放,並返回給全局組塊列表。類加載器持有的組塊又會被分紅多個塊,每個塊存儲一個單元的元信息。組塊中的塊是線性分配(指針碰撞分配形式)。組塊分配自內存映射區域。這些全局的虛擬內存映射區域以鏈表形式鏈接,一旦某個虛擬內存映射區域清空,這部份內存就會返回給操做系統。

上圖展現的是虛擬內存映射區域如何進行元組塊的分配。類加載器1和3代表使用了反射或者爲匿名類加載器,他們使用了特定大小組塊。 而類加載器2和4根據其內部條目的數量使用小型或者中型的組塊。

 

四、Metaspace相關參數

(1)-XX:MetaspaceSize,初始空間大小,達到該值就會觸發垃圾收集進行類型卸載,同時GC會對該值進行調整:若是釋放了大量的空間,就適當下降該值;若是釋放了不多的空間,那麼在不超過MaxMetaspaceSize時,適當提升該值。

(2)-XX:MaxMetaspaceSize,最大空間,默認是沒有限制的。

若是沒有使用-XX:MaxMetaspaceSize來設置類的元數據的大小,其最大可利用空間是整個系統內存的可用空間。JVM也能夠增長本地內存空間來知足類元數據信息的存儲。 可是若是沒有設置最大值,則可能存在bug致使Metaspace的空間在不停的擴展,會致使機器的內存不足;進而可能出現swap內存被耗盡;最終致使進程直接被系統直接kill掉。若是類元數據的空間佔用達到MaxMetaspaceSize設置的值,將會觸發對象和類加載器的垃圾回收。

(3)-XX:MinMetaspaceFreeRatio,在GC以後,最小的Metaspace剩餘空間容量的百分比,減小爲分配空間所致使的垃圾收集

(4)-XX:MaxMetaspaceFreeRatio,在GC以後,最大的Metaspace剩餘空間容量的百分比,減小爲釋放空間所致使的垃圾收集

 

 

參考文章:

(1)https://www.cnblogs.com/williamjie/p/9558094.html

(2)java面試:你真的知道metaspace?? https://www.jianshu.com/p/cd34d6f3b5b4

相關文章
相關標籤/搜索