
好的,我们将深入解析 Oracle 数据库共享池(Shared Pool)的内部内存结构。共享池是 SGA(系统全局区)中最复杂且至关重要的组件之一,理解其内部原理对于诊断库缓存(Library Cache)锁存器争用、内存不足错误(ORA-04031)以及 SQL 执行性能至关重要。
1. 共享池的核心作用
官方/专业解释
共享池的主要目的是缓存许多不同类型的程序数据,包括:
- 库缓存(Library Cache): 存储已解析的 SQL 语句(SQL Area)、PL/SQL 代码(过程、函数、包、触发器)、执行计划、解析树等。
- 数据字典缓存(Dictionary Cache / Row Cache): 缓存数据字典信息(如表、列定义、权限等),以减少对底层表的访问。
- 其它结构: 如控制结构、并行执行消息缓冲区等。
其核心目标是通过内存中共享的、可重用的代码和执行计划,来避免重复的解析操作(硬解析),从而提高数据库性能和可扩展性。
通俗解释
把共享池想象成一个学校的“公共教研室”。
- 库缓存: 就像教研室里的教案柜。老师们(会话)把写好的教案(SQL解析结果、执行计划)放在这里。如果张老师要上一堂和李老师一样的课(执行相同的SQL),他就不用重新写教案(硬解析),直接拿李老师的教案(软解析)来用就行了。这节省了大量时间和精力。
- 数据字典缓存: 就像教研室墙上的学校规章制度和课程表。老师们不用每次都跑去教务处(查询磁盘上的数据字典表)查信息,抬头看看墙上的公告(缓存)就能快速获取。
这个“教研室”的空间是有限的,所以需要一套高效的管理机制来决定哪些教案和公告可以留下,哪些需要被清理掉。
2. 内存结构:堆、区、Chunk 与子堆
共享池的内存管理采用一种堆(Heap) 式的内存管理器模型。它不是由固定大小的块组成(如Buffer Cache),而是由可变大小的内存片段管理。
A. 堆 (Heap)
- 官方/专业解释: 共享池本身就是一个堆(
KGH: Kernel Generic Heap)。一个堆是一个连续的虚拟内存段,从中可以分配更小的内存片段。共享池实际上由多个堆组成,例如:- 一个主堆,用于库缓存和大多数结构。
- 一个保留堆(Reserved Heap),专门为大于一定阈值(
_shared_pool_reserved_min_alloc)的大内存分配请求服务,以防止大分配导致主堆碎片化。
- 通俗解释: “教研室”本身就是一个大房间(主堆)。为了防止有人搬进来一个大柜子(大内存分配)把整个房间的布局打乱,学校在旁边又预留了一个小储藏室(保留堆),专门放这些大件物品。
B. 区 (Extent)
- 官方/专业解释: 堆在物理上是由一个或多个区组成的。区是操作系统分配给它的一组连续的物理内存页。当堆需要增长时,它会从操作系统分配新的区。
- 通俗解释: 学校给“教研室”一次性划拨了一整块地皮(区) 来盖这间房。如果后来教研室不够用了,学校就再在旁边划一块地皮(新的区)进行扩建。区是物理内存的分配单位。
C. Chunk(内存块)
- 官方/专业解释: Chunk 是共享池内存分配和管理的的基本单位。当需要在共享池中存储一个对象(如一条SQL的解析树)时,内存管理器会分配一个大小合适的、连续的Chunk来存放它。每个Chunk都有一个头部,包含其大小、类型、所属的堆、状态(空闲或已使用)等管理信息。
- 通俗解释: 教研室里的一个个“文件柜格子”或“桌面位置”。每个教案(SQL对象)都被装在一个大小刚好的格子(Chunk)里。格子是使用的的最小单位。
- 状态:
- 空闲Chunk (Free Chunk): 未被使用的格子,挂在空闲列表(Free List) 上。
- 已使用Chunk (Used Chunk): 已被对象占用的格子。
- 可重建Chunk (Recreatable Chunk): 库缓存中的大部分对象(如SQL语句)属于此类。如果内存不足,它们可以被 aged out(老化移出),之后如果需要可以重新解析并加载进来。
- 永久Chunk (Permanent Chunk): 数据字典缓存中的对象等,这些不能被 aged out。
D. 子堆 (Subheap)
- 官方/专业解释: 某些大型或复杂的对象(如一个非常大的PL/SQL包)可能无法存放在一个单一的Chunk中,或者其内部有自己独立的管理结构。这时,内存管理器会为这些对象分配一个子堆。子堆是主堆内部的一个逻辑上独立的内存管理单元,它自己也有区、Chunk和空闲列表。常见的子堆是
KGK堆,用于管理SQL Area。 - 通俗解释: 李老师写了一本非常厚的教学参考书(大对象),一个格子放不下。教研室主任就专门给他分配了一个带有多层隔板的小书柜(子堆) 放在教研室角落里。这个书柜内部的空间划分(子堆内的Chunk)是独立于主教研室的大格子系统的。
3. 内存分配原理与碎片化
-
分配过程: 当一个请求需要分配内存时(例如,一条新SQL被解析),内存管理器会扫描空闲列表(Free List),寻找一个足够大的空闲Chunk。
- 如果找到,则将其分割:一部分用于请求,剩余部分成为一个新的、更小的空闲Chunk。
- 如果找不到,内存管理器会尝试老化(Aging) 一些可重建的Chunk(基于LRU算法),将它们释放回空闲列表。
- 如果仍然找不到,则会报出
ORA-04031: unable to allocate ... shared memory错误。
-
碎片化 (Fragmentation):
- 问题: 经过频繁的分配和释放,空闲列表中会充满大量小的、不连续的空闲Chunk。虽然总的空闲内存可能很多,但当一个请求需要分配一个较大的、连续的内存块时,却无法找到合适的Chunk。这就是碎片化。
- 解决方案: 保留堆(Reserved Heap) 就是为了解决这个问题而设计的。大的分配请求(默认>4400字节)会直接去保留堆中申请,而不会在主堆中寻找,从而避免“大物件”拆散“小格子”。
4. 相关查询与管理 SQL 命令
A. 查看共享池总体信息
-- 查看SGA中共享池的大小
SELECT component, current_size / 1024 / 1024 "Size (MB)"
FROM v$sga_dynamic_components
WHERE component = 'shared pool';
-- 查看保留区的设置和使用情况
SELECT * FROM v$shared_pool_reserved;
- 关键字段
FREE_SPACE表示保留区中剩余空间。如果REQUEST_MISSES> 0,说明曾因在保留区分配失败而不得不去主堆寻找,这可能意味着需要增大shared_pool_reserved_size。
B. 深入查看内存结构(Chunk信息)
-- 查看共享池中Chunk的分布情况(需要DBA权限)
SELECT
kglhdpar || ' - ' || -- 父堆地址
DECODE(kglnahsh, 0, 'Perm', 1, 'Rcre', 'Free') chunk_type, -- 类型:永久,可重建,空闲
COUNT(*),
ROUND(SUM(ksmchsiz) / 1024) total_size_kb,
ROUND(AVG(ksmchsiz)) avg_size_bytes,
MIN(ksmchsiz) min_size,
MAX(ksmchsiz) max_size
FROM x$ksmsp -- 这是一个底层内部视图,直接查询共享池内存
GROUP BY kglhdpar, DECODE(kglnahsh, 0, 'Perm', 1, 'Rcre', 'Free')
ORDER BY total_size_kb DESC;
- 这个查询非常强大,但执行时可能持有闩锁,对生产系统性能有影响,切勿频繁执行!
- 它可以告诉你堆上有多少Chunk、它们的大小分布以及类型,是分析碎片化的终极工具。
C. 查看库缓存中的对象(了解“教案柜”里放了什么)
SELECT namespace, COUNT(*), SUM(sharable_mem)
FROM v$librarycache
GROUP BY namespace;
-- 查看具体SQL语句及其内存占用
SELECT sql_id, sql_text, sharable_mem, executions
FROM v$sql
WHERE sharable_mem > 100000 -- 查找占用内存较大的SQL
ORDER BY sharable_mem DESC;
D. 管理命令:解决内存问题和性能问题
-
刷新共享池(极端手段,慎用!):
ALTER SYSTEM FLUSH SHARED_POOL;- 作用: 清空库缓存和数据字典缓存中的所有可重建对象。所有SQL之后都需要重新解析(硬解析),短期内会造成性能陡降。
- 适用场景: 通常只在测试环境,或确认共享池中出现严重错误且内存碎片化无法通过其他手段解决时使用。
-
固定常用对象(防止被老化出去):
-- 使用DBMS_SHARED_POOL包(需要先运行@?/rdbms/admin/dbmspool.sql) EXEC DBMS_SHARED_POOL.KEEP('SCOTT.EMP_PKG', 'P'); -- 'P' for Procedure- 作用: 将重要的包、游标等标记为“永久”,使其不会被LRU算法老化出去。
-
调整共享池大小:
-- 如果使用自动内存管理(AMM) ALTER SYSTEM SET memory_target = 2G SCOPE=SPFILE; -- 如果使用自动共享内存管理(ASMM) ALTER SYSTEM SET sga_target = 1.5G SCOPE=SPFILE; ALTER SYSTEM SET shared_pool_size = 500M; -- 或在ASMM下由系统自动调整
总结
| 组件 | 官方角色 | 通俗比喻 | 管理要点 |
| :— | :— | :— | :— |
| 堆 (Heap) | 共享池内部的内存段 | 教研室的房间 | 分为主堆和保留堆 |
| 区 (Extent) | 从OS分配的连续物理内存 | 划拨的地皮 | 物理分配单位 |
| Chunk | 内存分配的基本单位 | 文件柜格子 | 核心管理单元,查看x$ksmsp了解详情 |
| 子堆 (Subheap) | 大对象内部的私有管理区 | 专属小书柜 | 用于管理大型SQL区域等 |
| 保留堆 | 处理大内存分配,防碎片 | 储藏室 | 监控v$shared_pool_reserved |
| 库缓存 | 存储SQL/PLSQL解析结果 | 教案柜 | 监控v$librarycache和v$sql |
理解共享池的堆、Chunk结构,是诊断和解决 ORA-04031 错误、库缓存锁存器争用(library cache latch / mutex)以及优化SQL解析性能的基础。通过提供的查询命令,你可以深入洞察共享池的内部状态,从而做出正确的管理和优化决策。
欢迎关注我的公众号《IT小Chen》
880

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



