冬眠的笔记
首页文章分类书单项目关于
冬眠
X

© 2026 冬眠的笔记 · 用文字记录思考,用思考改变生活

首页>文章>Java
JavaJVMMetaSpace元空间

元空间 MetaSpace 详解

JDK 8 引入的 MetaSpace 元空间设计、与永久代的差异以及内存溢出排查

冬眠
冬眠
专注于技术、阅读与思考
2025-11-19
发布日期
9 min read
阅读时长
浏览量
元空间 MetaSpace 详解

元空间是 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%时扩容

文章标签

JavaJVMMetaSpace元空间内存
SpringBoot 数据库连接配置
上一篇

SpringBoot 数据库连接配置

2025-11-19

Java 虚拟机配置
下一篇

Java 虚拟机配置

2025-11-19

冬眠

冬眠

博主

专注于技术、阅读与思考。在这里记录学习、思考与生活。

116
文章
2
分类
关注我
系列:JVM 实战

第 3 篇,共 3 篇

上一篇

Java 虚拟机配置

已是最后一篇

文章目录

目录

  • 存储内容
  • 配置参数
  • 监控
  • 空闲块
  • 调优

相关文章

查看更多
Java 虚拟机配置

Java 虚拟机配置

2025-11-19 · 5 min read

线程 FullGC 问题排查

线程 FullGC 问题排查

2025-11-19 · 10 min read

JWT 基础知识

JWT 基础知识

2025-11-19 · 7 min read