
好的,我们来深入探讨 Oracle 共享池内存管理中一个至关重要但常被忽视的机制:空闲列表(Free List)。它是共享池内存分配器的引擎,直接关系到分配效率和碎片化问题。
1. Free List 的核心作用与原理
官方/专业解释
空闲列表(Free List) 是共享池内存管理器内部维护的一个或多个链表结构。这些链表将所有状态为“空闲”(FREE)的 Chunk 组织起来,以便在接收到新的内存分配请求时,能够快速找到一块大小合适的内存空间。
共享池中并非只有一个 Free List。为了提升搜索效率,空闲列表通常按照 Chunk 的大小进行分桶(Bucket) 管理。例如,有一个链表专门链接所有 100-200 字节的空闲 Chunk,另一个链表管理 200-400 字节的,以此类推。
通俗解释
想象共享池是一个大型家用五金仓库,里面堆满了各种尺寸的螺丝、螺母、螺栓(这些就是 Chunk)。
- 没有 Free List: 老师傅需要找一个 M6x20 的螺丝。他不得不打开每一个零件盒,漫无目的地翻找,效率极低。
- 有 Free List: 仓库管理员非常专业,他有一个标签墙(Free List)。墙上有一个钩子挂着“M6 螺丝”的标签,下面串着一串所有空闲的 M6 螺丝;另一个钩子挂着“M8 螺丝”,下面串着所有 M8 螺丝。
当老师傅(数据库会话)需要某个零件(内存请求)时,管理员(内存管理器)直接走到对应的标签(Bucket)下,从链表中取出一个尺寸最匹配的零件交给他。这极大地提高了分配效率。
这个“标签墙”系统就是 Free List。它通过对空闲内存块进行分类,避免了每次分配时都要进行昂贵的“全局扫描”。
2. Free List 的工作流程
内存分配和释放的过程,本质上是 Free List 的更新过程。
A. 分配过程 (Allocation)
- 接收请求: 内存管理器收到一个请求,需要分配
X字节的内存。 - 查找桶: 管理器根据
X的大小,定位到对应的 Free List 大小桶。 - 搜索链表: 在该桶对应的链表中,从头开始扫描,寻找第一个大小大于等于
X的空闲 Chunk。 - 分割 Chunk:
- 如果找到的 Chunk 大小正好是
X,则直接将其从 Free List 上取下,标记为已使用,并返回给请求者。 - 如果找到的 Chunk 大小
M远大于X,则将其分割:开头的X字节分配给请求者,剩余的M-X字节形成一个新的、更小的空闲 Chunk,并被挂回到它对应大小的 Free List 桶中。
- 如果找到的 Chunk 大小正好是
- 分配失败: 如果在相应的桶里找不到足够大的 Chunk,内存管理器会尝试在其他更大的桶中寻找,或者触发 LRU 老化机制,将一些
recr或freeable类型的 Chunk 释放为freeChunk,再将其加入 Free List,然后重试分配。
B. 释放过程 (Freeing)
- 标记空闲: 当一个对象被 aged out 或不再需要时,它占用的 Chunk 被标记为
FREE。 - 合并(Coalescing): 在将其挂回 Free List 之前,内存管理器会检查与该 Chunk物理地址相邻的内存块是否也是空闲的。
- 如果是,则将这两个(或更多)小的空闲 Chunk 合并(Coalesce) 成一个大的空闲 Chunk。
- 这是对抗内存碎片化的关键步骤。
- 挂入链表: 将最终的空闲 Chunk(可能是合并后的)挂到其大小对应的 Free List 桶中。
通俗解释
继续五金仓库的比喻:
- 分配: 老师傅要一个 20mm 的螺丝。管理员在“20mm螺丝”的钩子(Free List 桶)下找。如果没有,他可能会找一个 30mm 的,用切割机切下 20mm 给老师傅,然后把剩下的 10mm 螺丝挂到“10mm螺丝”的钩子上。
- 释放与合并: 老师傅还回来两个相邻的 10mm 螺丝(两个小的空闲 Chunk)。管理员发现它们原来是从一个 20mm 螺丝切下来的,就把它们焊接回去,重新变成一个 20mm 螺丝,挂回对应的钩子。这样下次就又能满足20mm的需求了。
- 如果不合并: 仓库里就会充满一堆 10mm 的小螺丝,虽然总长度可能很长,但当有人需要一個 20mm 的螺丝时,却找不到一个完整的,这就是碎片化。
3. 保留空闲列表 (Reserved Free List)
除了管理主堆(Main Heap)的 Free Lists,还有一个独立的 保留池(Reserved Pool),它也有自己的 Free List。
- 目的: 专门处理大内存分配请求(大小超过
_shared_pool_reserved_min_alloc隐含参数,通常约为 4400 字节)。 - 原理: 大的分配请求直接从这个保留池的 Free List 中获取空间,而不是去主堆中寻找。这避免了在主堆中分割出一个巨大的 Chunk,从而有效地防止了大块内存分配导致的主堆碎片化。
- 监控: 通过
V$SHARED_POOL_RESERVED视图监控。
4. 相关查询与管理 SQL 命令
查询 1:诊断 Free List 和碎片化(核心查询)
此查询按 Chunk 大小范围统计空闲内存的分布,是诊断碎片化的黄金命令。
SELECT
'0-500 bytes' AS size_range,
COUNT(*) AS chunks,
SUM(ksmchsiz) AS total_bytes
FROM x$ksmsp
WHERE ksmchcls = 'free'
AND ksmchsiz BETWEEN 0 AND 500
UNION ALL
SELECT
'500-1000 bytes',
COUNT(*),
SUM(ksmchsiz)
FROM x$ksmsp
WHERE ksmchcls = 'free'
AND ksmchsiz BETWEEN 500 AND 1000
UNION ALL
SELECT
'1000-2000 bytes',
COUNT(*),
SUM(ksmchsiz)
FROM x$ksmsp
WHERE ksmchcls = 'free'
AND ksmchsiz BETWEEN 1000 AND 2000
UNION ALL
SELECT
'2000-5000 bytes',
COUNT(*),
SUM(ksmchsiz)
FROM x$ksmsp
WHERE ksmchcls = 'free'
AND ksmchsiz BETWEEN 2000 AND 5000
UNION ALL
SELECT
'>5000 bytes',
COUNT(*),
SUM(ksmchsiz)
FROM x$ksmsp
WHERE ksmchcls = 'free'
AND ksmchsiz > 5000
ORDER BY total_bytes DESC;
结果分析:
- 健康状态: 总空闲内存(
total_bytes)大部分分布在>5000 bytes和2000-5000 bytes的范围内。这表明有大块的连续空间可供分配。 - 碎片化状态: 如果总空闲内存很大,但绝大部分都由成千上万个
0-500 bytes的小 Chunk 组成,而>5000 bytes的 Chunk 很少甚至没有,这就表明严重碎片化。此时,虽然总空间足够,但一个大请求(如加载一个大包)可能无法找到连续空间,从而触发ORA-04031错误。
查询 2:监控保留池 Free List 的健康状况
SELECT free_space,
requests,
request_misses,
request_failures,
last_failure_size
FROM v$shared_pool_reserved;
关键字段:
REQUEST_MISSES: 表示在保留池中分配失败、不得不fallback到主堆中去寻找的次数。如果这个值持续增长,说明保留池大小可能不足。LAST_FAILURE_SIZE: 最近一次失败所请求的大小。REQUEST_FAILURES: 表示即使在主堆中也分配失败的次数,这通常会直接导致ORA-04031。
查询 3:查看最大的空闲 Chunk
直接找到当前最大的空闲块,其大小决定了能否满足大请求。
SELECT MAX(ksmchsiz) AS largest_free_chunk
FROM x$ksmsp
WHERE ksmchcls = 'free';
5. 管理命令与优化建议
-
优化应用(根本解决):
- 使用绑定变量: 这是最重要的优化。它从根本上减少了共享池中 Chunk 的数量和大小波动,从而显著减轻 Free List 的管理压力和碎片化程度。
-
调整保留池大小:
- 如果
V$SHARED_POOL_RESERVED显示REQUEST_MISSES很高,可以增加保留池大小。
ALTER SYSTEM SET shared_pool_reserved_size = 150M; -- 通常设为主共享池的5%-10% - 如果
-
增加共享池大小:
- 如果碎片化严重且总内存不足,这是最直接的方法。更大的池能容纳更大的空闲 Chunk。
ALTER SYSTEM SET shared_pool_size = 3G; -
终极手段:刷新共享池:
ALTER SYSTEM FLUSH SHARED_POOL;- 作用: 这会释放所有
recr和freeableChunk,将它们变为freeChunk,并且在这个过程中,内存管理器会执行彻底的合并。执行后,Free List 上通常会剩下少数几个非常大的空闲 Chunk。 - 代价: 所有SQL之后都需要硬解析,会导致短期性能暴跌。仅在其他方法无效且系统可接受短暂性能冲击时使用。
- 作用: 这会释放所有
通过深入理解 Free List 的工作原理,并利用提供的查询进行监控,你可以主动地管理和优化共享池,避免其陷入碎片化状态,从而确保数据库的稳定性和高性能。
欢迎关注我的公众号《IT小Chen》
1416

被折叠的 条评论
为什么被折叠?



