Java 空闲列表(Free List) 是 JVM 在堆内存分配中用于管理非连续内存碎片的核心机制。它的核心作用是为对象分配寻找可用内存空间,尤其适用于内存不规整的场景(如老年代内存碎片化时)。以下是其工作原理和关键细节:
数据结构
JVM 维护一个链表结构(空闲链表),每个节点记录一块空闲内存的起始地址和大小。
0x1000~0x2000 (4KB) → 0x3000~0x4000 (4KB) → ...
分配流程
老年代内存分配
新生代 Survivor 区(特定回收器)
部分 GC 算法(如 Serial/Parallel Scavenge)在 Survivor 区也使用空闲列表管理碎片。
分配方式 | 适用条件 | 性能 | 内存状态 |
---|---|---|---|
空闲列表 | 内存不规整(碎片化) | 较慢(需遍历链表) | 非连续空间 |
指针碰撞 | 内存规整(无碎片) | 极快(移动指针即可) | 连续空间(如复制算法) |
指针碰撞(Bump The Pointer):在连续内存中通过简单移动指针分配空间(如 Eden 区分配)。
通过内存分配模拟碎片化场景(需搭配 JVM 参数):
// 持续分配大对象触发老年代碎片
List<byte[]> list = new ArrayList<>();
while (true) {
// 分配1MB对象(直接进入老年代)
byte[] data = new byte[1 * 1024 * 1024];
list.add(data);
}
关键 JVM 参数:
-XX:+UseSerialGC # 使用 Serial 收集器(老年代依赖空闲列表)
-XX:PretenureSizeThreshold=1M # 对象>1MB直接分配老年代
-XX:+PrintGCDetails # 打印GC日志观察碎片现象
日志现象:多次 Full GC 后出现 java.lang.OutOfMemoryError: Java heap space
,即使堆仍有空闲总量(碎片导致)。