元空间是 JVM 1.8 版本引入的一种新的内存区域,替代永久代(PermGen)的内存区域,用于存储与类加载相关的元数据信息。
存储内容
类的结构信息
类的基本定义:包括类名、父类信息、接口列表、修饰符(如 public、abstract)等
字段与方法信息:字段名称、类型、修饰符;方法名称、参数列表、返回类型、字节码等
类的运行结构:JVM 通过这些信息解析类结构、分配对象内存及调用方法
常量池
常量池是类加载后,在方法区中的一块内存区域,用于存储类的常量、静态变量、字符串等。
字符串常量:如 String str = "Hello"中的 "Hello",编译后存储在常量池中供共享引用
符号引用:对其他类、方法或字段的引用,运行时解析为实际地址
基本类型常量:如整数、浮点数常量
方法的字节码
存储编译后生成的字节码指令,供 JVM 解释执行或 JIT 编译优化
反射信息
反射 API(如 Class.getMethod())所需的元数据,支持运行时动态操作类结构
静态变量
类的静态成员变量(如 public static int count;),生命周期与类绑定,存储在元空间而非堆中
运行时常量
运行时生成的常量(如 public static final int RANDOM_CONST = new Random().nextInt(100);),值在程序启动时确定
配置参数
MetaspaceSize 初始化元空间大小
MaxMetaspaceSize 限制元空间大小上限
如果元空间的大小超过了 MaxMetaspaceSize,JVM 会抛出 OutOfMemoryError 异常。
监控
jconsole 监控
jps 获取应用的 pid, jconsole <pid> 开启 jconsole 监控
$ jps
24709 Launcher
6343 Main
36253 Jps
$ jconsole 6343
# 碎片诊断, Free in chunks in use >10%→ 碎片化严重, Waste >5%→ 需调整分配策略
$ jcmd <pid> VM.metaspace scale=MB | grep "Free in chunks"
在 jconsole 中查看元空间的使用情况

jcmd 监控
jcmd 是 JDK 提供的一个命令行工具,用于监控和管理 Java 进程。
jcmd 监控元空间的使用情况 jcmd <pid> VM.metaspace.
$ jcmd 6343 VM.metaspace
下面是一个 jcmd 监控元空间的输出结果
218:
# 6539 个活跃类加载器,加载 62016 个类
Total Usage - 6539 loaders, 62016 classes (1441 shared):
# 非类空间(Non-Class) >99%使用率(375.62 MB / 378.52 MB),存储常量池、方法字节码等
Non-Class: 31542 chunks, 378.52 MB capacity, 378.27 MB (>99%) committed, 375.62 MB (>99%) used, 2.63 MB ( <1%) free, 22.74 KB ( <1%) waste , deallocated: 3934 blocks with 1.73 MB
# 类空间(Class) 91% 使用率(39.16 MB / 42.88 MB),存储 Klass 结构等类元数据
Class: 9210 chunks, 42.88 MB capacity, 42.82 MB (>99%) committed, 39.16 MB ( 91%) used, 3.66 MB ( 9%) free, 768 bytes ( <1%) waste , deallocated: 2413 blocks with 595.93 KB
# 使用率 98% 414.78MB / 421.40 MB
Both: 40752 chunks, 421.40 MB capacity, 421.09 MB (>99%) committed, 414.78 MB ( 98%) used, 6.28 MB ( 1%) free, 23.49 KB ( <1%) waste , deallocated: 6347 blocks with 2.32 MB
# 虚拟空间分配
Virtual space:
# 非类空间:保留 384 MB,提交 378.31 MB(99%),含 6 个 2MB 的虚拟空间节点(Node)
Non-class space: 384.00 MB reserved, 378.31 MB ( 99%) committed, 6 nodes.
# 类空间:保留 416 MB(CompressedClassSpaceSize),仅提交 10%(42.88 MB),说明预分配空间未被充分利用
Class space: 416.00 MB reserved, 42.88 MB ( 10%) committed, 1 nodes.
Both: 800.00 MB reserved, 421.19 MB ( 53%) committed.
# 元空间内存被划分为不同层级的chunk,包括specialized/small/medium/humongous等类型
# 所有chunk的committed都是0,说明这些是空闲且已释放物理内存的块。操作系统已回收物理内存,仅保留虚拟地址空间,当新类加载器需要分配内存时,系统会重新提交物理内存(按需分配)
# capacity值显示内存虽然虚拟保留但实际未占用
# 存在多个中小尺寸的chunk(4m/1m到4k),但缺乏16m/8m等大块,暗示内存碎片化问题,碎片化会降低大内存请求的分配效率(例如申请 6MB 时需合并多个小空闲块)
Chunk freelists:
Non-Class:
16m: (none)
8m: (none)
4m: 2, capacity=8.00 MB, committed=0 bytes ( 0%)
2m: (none)
1m: 2, capacity=2.00 MB, committed=0 bytes ( 0%)
512k: (none)
256k: 2, capacity=512.00 KB, committed=0 bytes ( 0%)
128k: 2, capacity=256.00 KB, committed=0 bytes ( 0%)
64k: 2, capacity=128.00 KB, committed=0 bytes ( 0%)
32k: 2, capacity=64.00 KB, committed=0 bytes ( 0%)
16k: (none)
8k: 2, capacity=16.00 KB, committed=0 bytes ( 0%)
4k: 2, capacity=8.00 KB, committed=0 bytes ( 0%)
2k: (none)
1k: (none)
Total word size: 10.96 MB, committed: 0 bytes ( 0%)
Class:
16m: (none)
8m: (none)
4m: 1, capacity=4.00 MB, committed=0 bytes ( 0%)
2m: (none)
1m: 1, capacity=1.00 MB, committed=0 bytes ( 0%)
512k: (none)
256k: (none)
128k: (none)
64k: 1, capacity=64.00 KB, committed=0 bytes ( 0%)
32k: 1, capacity=32.00 KB, committed=0 bytes ( 0%)
16k: 1, capacity=16.00 KB, committed=0 bytes ( 0%)
8k: (none)
4k: 1, capacity=4.00 KB, committed=0 bytes ( 0%)
2k: 1, capacity=2.00 KB, committed=0 bytes ( 0%)
1k: (none)
Total word size: 5.12 MB, committed: 0 bytes ( 0%)
Both:
16m: (none)
8m: (none)
4m: 3, capacity=12.00 MB, committed=0 bytes ( 0%)
2m: (none)
1m: 3, capacity=3.00 MB, committed=0 bytes ( 0%)
512k: (none)
256k: 2, capacity=512.00 KB, committed=0 bytes ( 0%)
128k: 2, capacity=256.00 KB, committed=0 bytes ( 0%)
64k: 3, capacity=192.00 KB, committed=0 bytes ( 0%)
32k: 3, capacity=96.00 KB, committed=0 bytes ( 0%)
16k: 1, capacity=16.00 KB, committed=0 bytes ( 0%)
8k: 2, capacity=16.00 KB, committed=0 bytes ( 0%)
4k: 3, capacity=12.00 KB, committed=0 bytes ( 0%)
2k: 1, capacity=2.00 KB, committed=0 bytes ( 0%)
1k: (none)
Total word size: 16.08 MB, committed: 0 bytes ( 0%)
Waste (unused committed space):(percentages refer to total committed size 421.19 MB):
Waste in chunks in use: 23.49 KB ( <1%)
Free in chunks in use: 6.28 MB ( 1%)
In free chunks: 0 bytes ( 0%)
Deallocated from chunks in use: 2.32 MB ( <1%) (6347 blocks)
-total-: 8.62 MB ( 2%)
chunk header pool: 40768 items, 2.81 MB.
Internal statistics:
num_allocs_failed_limit: 0.
num_arena_births: 26200.
num_arena_deaths: 13122.
num_vsnodes_births: 7.
num_vsnodes_deaths: 0.
num_space_committed: 6773.
num_space_uncommitted: 29.
num_chunks_returned_to_freelist: 18449.
num_chunks_taken_from_freelist: 59202.
num_chunk_merges: 5790.
num_chunk_splits: 30832.
num_chunks_enlarged: 13994.
num_inconsistent_stats: 0.
# 元空间配置
Settings:
# 元空间最大大小
MaxMetaspaceSize: 512.00 MB
# 类指针压缩空间上限
CompressedClassSpaceSize: 416.00 MB
# 推迟首次元空间GC触发时机,推荐 512M
Initial GC threshold: 256.00 MB
Current GC threshold: 512.00 MB
CDS: on
- commit_granule_bytes: 65536.
- commit_granule_words: 8192.
- virtual_space_node_default_size: 8388608.
- enlarge_chunks_in_place: 1.
- use_allocation_guard: 0.
空闲块
基本单位:Chunk(内存块) 元空间将内存划分为不同大小的 Chunk,作为内存分配和回收的基本单位。 每个 Chunk被标记为特定规格(如 4m、1m、256k等),表示其容量大小。
空闲块来源
当类加载器卸载时,其占用的 Chunk会被释放并加入 freelist(空闲列表),形成待分配的内存池
复用机制
新类加载器申请内存时,优先从 freelist中匹配尺寸合适的空闲 Chunk分配,避免频繁向操作系统申请新内存

调优
启用弹性元空间
-XX:+UseElasticMetaspace # Java 16默认启用,需升级JDK
-XX:MetaspaceReclaimPolicy=aggressive # 激进归还内存
关键改进: 动态块大小:根据类加载需求分配更匹配的内存块,减少内部碎片。 块合并机制:合并相邻空闲块,形成连续大内存。
效果:碎片率降低50%~70%,内存归还速度提升3倍。
MetaspaceReclaimPolicy 的策略选项
- aggressive:激进归还内存,适合内存敏感场景;
- balanced(默认):平衡内存与性能;
- none:禁用主动归还。
优化类卸载和垃圾回收
启用并发类卸载
-XX:+ClassUnloading -XX:+ClassUnloadingWithConcurrentMark
协同GC调优
ZGC/Shenandoah:优先选择低延迟GC,减少元空间回收停顿
-XX:+UseZGC # 或 -XX:+UseShenandoahGC
-XX:ZCollectionInterval=10 # ZGC每10秒触发一次回收
G1调优
-XX:+UseG1GC -XX:G1MetaspaceGrowThreshold=35 # 元空间占用超35%时扩容
文章标签
冬眠
博主专注于技术、阅读与思考。在这里记录学习、思考与生活。
第 3 篇,共 3 篇
