瞭解到什麼是ccs區,一般都是實際執行了jstat -gc 之後,看Java堆的gc相關的幾個分區的gc信息,前面的s0,s1,e區,o區,還好猜,研究過分區的,不難猜出來這個分區是啥意思,M區雖然不知道是Metaspace元空間,但是錯把這個M區當成Method area 方法區,也說的過去。這個ccsc就不好說了。之前的看的文章都沒人說這個區是啥。
Java之jstat的用法:Java虛擬機 統計信息查看 工具
不瞭解這幾個簡寫單詞是啥意思的,可以參考一下之前的這個jstat的文章,裏面對每一列的title的簡寫都做了解釋。
什麼是 Compressed Class Space
在 64 位平臺上,HotSpot 使用了兩個壓縮優化技術,Compressed Object Pointers (“CompressedOops”) 和 Compressed Class Pointers。
壓縮指針,指的是在 64 位的機器上,使用 32 位的指針來訪問數據(堆中的對象或 Metaspace 中的元數據)的一種方式。
這樣有很多的好處,比如 32 位的指針佔用更小的內存,可以更好地使用緩存,在有些平臺,還可以使用到更多的寄存器。
當然,在 64 位的機器中,最終還是需要一個 64 位的地址來訪問數據的,所以這個 32 位的值是相對於一個基準地址的值。
下面將描述 Compressed Class Pointers:
每個 Java 對象,在它的頭部,有一個引用指向 Metaspace 中的 Klass 結構。
當使用了 compressed class pointers,這個引用是 32 位的值,爲了找到真正的 64 位地址,需要加上一個 base 值:
上面的內容應該很好理解,這項技術對 Klass 的分配帶來的問題是:由於 32 位地址只能訪問到 4G 的空間,所以最大隻允許 4G 的 Klass 地址。這項限制也意味着,JVM 需要向 Metaspace 分配一個連續的地址空間。
當從系統申請內存時,通過調用系統接口 malloc(3) 或 mmap(3),操作系統可能返回任意一個地址值,所以在 64位系統中,它並不能保證在 4G 的範圍內。
所以,我們只能用一個 mmap() 來申請一個區域單獨用來存放 Klass 對象。我們需要提前知道這個區域的大小,而且不能超過 4G。顯然,這種方式是不能擴展的,因爲這個地址後面的內存可能是被佔用的。
只有 Klass 結構有這個限制,對於其他的 class metadata 沒有這個必要: 因爲只有 Klass 實例是通過 Java 對象 header 中的壓縮指針訪問的。其他的 metadata 都是通過 64 位的地址進行訪問的,所以它們可以被放到任意的地址上。
所以,我們決定將 Metaspace 分爲兩個區域:non-class part 和 class part。
- class part:存放 Klass 對象,需要一個連續的不超過 4G 的內存
- non-class part:包含其他的所有 metadata
class part 被稱作 Compressed Class Space,這個名字會有點怪,因爲 Klass 本身其實沒有使用壓縮技術,而是引用它們的指針被壓縮了。
compressed class space 空間的大小,是通過 -XX:CompressedClassSpaceSize 指定的。
我們需要提前知道自己需要多少內存,它的默認值是 1G。當然這個 1G 並不是真的使用了操作系統的 1G,而是虛擬地址映射。
開關: UseCompressedClassPointers, UseCompressedOops
-XX:+UseCompressedOops
允許對象指針壓縮。
-XX:+UseCompressedClassPointers
允許類指針壓縮。
它們默認都是開啓的,可以手動關閉它們。
如果不允許類指針壓縮,那麼將沒有 compressed class space 這個空間,並且-XX:CompressedClassSpaceSize
這個參數無效。
-XX:-UseCompressedClassPointers
需要搭配 -XX:+UseCompressedOops
,但是反過來不是: 我們可以只壓縮對象指針,不壓縮類指針。
這裏面爲什麼這麼規定我也不懂,但是從直覺上來說,壓縮對象指針顯然是比較重要的,能獲得較大的收益。也許就是基於這種考量吧:你連對象指針都不壓縮,類指針壓縮不壓縮又有什麼關係呢?
注意,對象指針壓縮要求堆小於 32G,所以如果堆大於等於 32G,那麼對象指針壓縮和類指針壓縮都會被關閉。
再多的消化不了拉。
參考: