序
本文主要研究一下jvm的CompressedClassSpace
CompressedClassSpace
- java8移除了permanent generation,然後class metadata儲存在native memory中,其大小預設是不受限的,可以通過-XX:MaxMetaspaceSize來限制
- 如果開啟了-XX:+UseCompressedOops及-XX:+UseCompressedClassesPointers(
預設是開啟
),則UseCompressedOops會使用32-bit的offset來代表java object的引用,而UseCompressedClassPointers則使用32-bit的offset來代表64-bit程式中的class pointer;可以使用CompressedClassSpaceSize來設定這塊的空間大小 - 如果開啟了指標壓縮,則CompressedClassSpace分配在MaxMetaspaceSize裡頭,即MaxMetaspaceSize=Compressed Class Space Size + Metaspace area (excluding the Compressed Class Space) Size
檢視CompressedClassSpace大小
jcmd pid GC.heap_info
/ # jcmd 1 GC.heap_info
1:
Shenandoah Heap
524288K total, 144896K committed, 77232K used
2048 x 256K regions
Status: not cancelled
Reserved region:
- [0x00000000e0000000, 0x0000000100000000)
Metaspace used 45675K, capacity 46867K, committed 47104K, reserved 1091584K
class space used 5406K, capacity 5838K, committed 5888K, reserved 1048576K
複製程式碼
可以看到整個metaspace使用了45675K,其中class space使用了5406K,而Metaspace area (excluding the Compressed Class Space)使用了45675K-5406K=40269K;整個metaspace的reserved大小為1091584K,其中class space的reserved大小為1048576K
jcmd pid VM.native_memory
/ # jcmd 1 VM.native_memory
1:
Native Memory Tracking:
Total: reserved=2224403KB, committed=238187KB
- Java Heap (reserved=524288KB, committed=144896KB)
(mmap: reserved=524288KB, committed=144896KB)
- Class (reserved=1092940KB, committed=48460KB)
(classes #8563)
( instance classes #7988, array classes #575)
(malloc=1356KB #20589)
(mmap: reserved=1091584KB, committed=47104KB)
( Metadata: )
( reserved=43008KB, committed=41216KB)
( used=40286KB)
( free=930KB)
( waste=0KB =0.00%)
( Class space:)
( reserved=1048576KB, committed=5888KB)
( used=5407KB)
( free=481KB)
( waste=0KB =0.00%)
- Thread (reserved=37130KB, committed=2846KB)
(thread #36)
(stack: reserved=36961KB, committed=2676KB)
(malloc=127KB #189)
(arena=42KB #70)
- Code (reserved=529360KB, committed=15420KB)
(malloc=968KB #4745)
(mmap: reserved=528392KB, committed=14452KB)
- GC (reserved=21844KB, committed=7724KB)
(malloc=5460KB #9644)
(mmap: reserved=16384KB, committed=2264KB)
- Compiler (reserved=165KB, committed=165KB)
(malloc=34KB #455)
(arena=131KB #5)
- Internal (reserved=3758KB, committed=3758KB)
(malloc=1710KB #6582)
(mmap: reserved=2048KB, committed=2048KB)
- Other (reserved=32KB, committed=32KB)
(malloc=32KB #3)
- Symbol (reserved=10277KB, committed=10277KB)
(malloc=7456KB #225421)
(arena=2821KB #1)
- Native Memory Tracking (reserved=4235KB, committed=4235KB)
(malloc=10KB #126)
(tracking overhead=4225KB)
- Arena Chunk (reserved=176KB, committed=176KB)
(malloc=176KB)
- Logging (reserved=7KB, committed=7KB)
(malloc=7KB #264)
- Arguments (reserved=18KB, committed=18KB)
(malloc=18KB #500)
- Module (reserved=165KB, committed=165KB)
(malloc=165KB #1708)
- Safepoint (reserved=4KB, committed=4KB)
(mmap: reserved=4KB, committed=4KB)
- Unknown (reserved=4KB, committed=4KB)
(mmap: reserved=4KB, committed=4KB)
複製程式碼
可以看到class部分,reserved大小為1092940KB,其中Metadata的reserved大小為43008KB,Class space的reserved大小為1048576KB;其中Metadata使用了40286KB,而Class space使用了5407KB
jmx檢視
@GetMapping("/meta")
public Object getMetaspaceSize(){
return ManagementFactory.getPlatformMXBeans(MemoryPoolMXBean.class)
.stream()
.filter(e -> MemoryType.NON_HEAP == e.getType())
.filter(e -> e.getName().equals("Metaspace") || e.getName().equals("Compressed Class Space"))
.map(e -> "name:"+e.getName()+",info:"+e.getUsage())
.collect(Collectors.toList());
}
複製程式碼
輸出如下:
/ # curl -i localhost:8080/memory/meta
HTTP/1.1 200
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 31 Mar 2019 03:06:55 GMT
["name:Metaspace,info:init = 0(0K) used = 46236784(45153K) committed = 47710208(46592K) max = -1(-1K)","name:Compressed Class Space,info:init = 0(0K) used = 5482736(5354K) committed = 6029312(5888K) max = 1073741824(1048576K)"]
複製程式碼
這裡可以看到Metaspace總共使用了45153K,其中Compressed Class Space部分使用了5354K,而Metaspace area (excluding the Compressed Class Space)使用了45153K-5354K=39799K;而這裡顯示的Metaspace的max為-1,其中Compressed Class Space部分max值為1048576K即1G
spring boot應用檢視
/ # curl -i "http://localhost:8080/actuator/metrics/jvm.memory.used?tag=area:nonheap"
HTTP/1.1 200
Content-Disposition: inline;filename=f.txt
Content-Type: application/vnd.spring-boot.actuator.v2+json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 31 Mar 2019 02:52:51 GMT
{"name":"jvm.memory.used","description":"The amount of used memory","baseUnit":"bytes","measurements":[{"statistic":"VALUE","value":6.4449464E7}],"availableTags":[{"tag":"id","values":["CodeHeap 'non-profiled nmethods'","CodeHeap 'profiled nmethods'","Compressed Class Space","Metaspace","CodeHeap 'non-nmethods'"]}]}
/ # curl -i "http://localhost:8080/actuator/metrics/jvm.memory.used?tag=area:nonheap&tag=id:Metaspace"
HTTP/1.1 200
Content-Disposition: inline;filename=f.txt
Content-Type: application/vnd.spring-boot.actuator.v2+json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 31 Mar 2019 02:54:56 GMT
{"name":"jvm.memory.used","description":"The amount of used memory","baseUnit":"bytes","measurements":[{"statistic":"VALUE","value":4.7468312E7}],"availableTags":[]}
/ # curl -i "http://localhost:8080/actuator/metrics/jvm.memory.used?tag=area:nonheap&tag=id:Compressed%
20Class%20Space"
HTTP/1.1 200
Content-Disposition: inline;filename=f.txt
Content-Type: application/vnd.spring-boot.actuator.v2+json;charset=UTF-8
Transfer-Encoding: chunked
Date: Sun, 31 Mar 2019 02:55:18 GMT
{"name":"jvm.memory.used","description":"The amount of used memory","baseUnit":"bytes","measurements":[{"statistic":"VALUE","value":5609952.0}],"availableTags":[]}
複製程式碼
springboot使用micrometer,通過/actuator/metrics介面提供相關指標查詢功能,其中Metaspace及Compressed Class Space在jvm.memory.used這個metric中 它是基於MemoryPoolMXBean來實現的,具體詳見micrometer-core-1.1.3-sources.jar!/io/micrometer/core/instrument/binder/jvm/JvmMemoryMetrics.java
小結
- java8移除了permanent generation,然後class metadata儲存在native memory中,其大小預設是不受限的,可以通過-XX:MaxMetaspaceSize來限制;如果開啟了-XX:+UseCompressedOops及-XX:+UseCompressedClassesPointers(
預設是開啟
),則UseCompressedOops會使用32-bit的offset來代表java object的引用,而UseCompressedClassPointers則使用32-bit的offset來代表64-bit程式中的class pointer;可以使用CompressedClassSpaceSize來設定這塊的空間大小 - 開啟了指標壓縮,則CompressedClassSpace分配在MaxMetaspaceSize裡頭,即MaxMetaspaceSize=Compressed Class Space Size + Metaspace area (excluding the Compressed Class Space) Size
- 檢視CompressedClassSpace的記憶體使用情況有好幾種方法:
- jcmd pid GC.heap_info(
Metaspace為總的部分,包含了class space,而Metaspace area (excluding the Compressed Class Space)需要自己計算即total-class space
) - jcmd pid VM.native_memory(
class為總的部分,包含了Metaspace area (excluding the Compressed Class Space)及Class Space
) - 使用JMX來獲取NON_HEAP型別中的name為Metaspace及Compressed Class Space的MemoryPoolMXBean可以得到Metaspace及Compressed Class Space的使用情況(
JMX得到的Metaspace為總的部分,而Metaspace area (excluding the Compressed Class Space)需要自己計算即total-class space
) - 如果是springboot應用,它使用micrometer,通過/actuator/metrics介面提供相關指標查詢功能,其中Metaspace及Compressed Class Space在jvm.memory.used這個metric中
- jcmd pid GC.heap_info(