本文将 DM8 内存问题统一归入三个分析对象:
- MPOLL(Memory Pool):关注池规模、使用、扩展、Target、Backup Pool 以及资源来源。
- Buffer:关注缓冲区规模、空闲页和淘汰行为。
- SQL Runtime:关注 Session/VM 运行时内存,以及 SORT、HASH 等 SQL 执行过程的内存消耗。
DM8 内存结构包含BUFFER和Memory Pool
SELECT
(SELECT SUM(N_PAGES * PAGE_SIZE) / 1024 / 1024
FROM V$BUFFERPOOL) AS BUFFER_SIZE_MB,
(SELECT SUM(TOTAL_SIZE) / 1024 / 1024
FROM V$MEM_POOL) AS MEM_POOL_MB,
(
(SELECT SUM(N_PAGES * PAGE_SIZE) / 1024 / 1024
FROM V$BUFFERPOOL)
+
(SELECT SUM(TOTAL_SIZE) / 1024 / 1024
FROM V$MEM_POOL)
) AS TOTAL_SIZE_MB
FROM DUAL;
这里的 TOTAL_SIZE_MB 是 DM 内存结构分析口径。当DM内存增长时,需要判断是Buffer还是Memory Pool增长。
核心视图:
SELECT
NAME,
IS_SHARED,
IS_OVERFLOW,
ORG_SIZE / 1024.0 / 1024.0 AS ORG_MB,
TOTAL_SIZE / 1024.0 / 1024.0 AS TOTAL_MB,
RESERVED_SIZE / 1024.0 / 1024.0 AS RESERVED_MB,
DATA_SIZE / 1024.0 / 1024.0 AS DATA_MB,
TARGET_SIZE,
N_EXTEND_NORMAL,
N_EXTEND_EXCLUSIVE,
PEAK_SIZE
FROM V$MEM_POOL
ORDER BY TOTAL_SIZE DESC;
重点字段:
| 字段 | 关注点 |
|---|---|
NAME |
哪个内存池 |
ORG_SIZE |
初始规模 |
TOTAL_SIZE |
当前总规模,包括扩展 |
RESERVED_SIZE |
当前已分配规模 |
DATA_SIZE |
实际有效数据规模 |
TARGET_SIZE |
目标规模 |
N_EXTEND_NORMAL |
Target 范围内扩展次数 |
N_EXTEND_EXCLUSIVE |
超过 Target 的扩展次数 |
IS_OVERFLOW |
是否涉及备用池 |
PEAK_SIZE |
历史峰值 |
建议重点观察:
TOTAL_SIZE是否超过 TARGET_SIZE
N_EXTEND_EXCLUSIVE 是否持续增加
IS_OVERFLOW 是否出现
其中,TOTAL_SIZE > TARGET_SIZE 说明发生过超过目标规模的扩展,但扩展本身不等于异常。需要结合持续时间、业务负载以及释放情况判断。
Memory Pool 的基本运行过程:
Original Size ↓ 正常使用 ↓ 空间不足 ↓ 扩展 ↓ 达到 Target ↓ 仍可继续扩展 ↓ 对象释放 ↓ 超出 Target 的部分可释放
因此:
RESERVED_SIZE 明显小于初始规模:可以作为池较空闲的观察信号;TOTAL_SIZE 长期高于 TARGET_SIZE:关注池外扩展;N_EXTEND_EXCLUSIVE 持续增长:分析为什么长期超过 Target;IS_OVERFLOW 表示使用了备用资源,需要重点关注。技术指导资料强调应尽量保持各内存池自持,减少池外分配。
现场不能只停留在“哪个 Pool 大”,还要继续回答:
具体模块 ↓ 具体 Pool ↓ Shared Pool ↓ OS
当某个 Pool 达到 Target 后仍需要内存时,可以继续向 Shared Pool 获取;Shared Pool 资源不足时可能继续向 OS 申请。
如果出现:
out of memory, fail to allocate memory from mem pool: BACKUP POOL
应高度重视。资料中的场景表明,使用 Backup Pool 后仍可能进一步触发 OS OOM。
Shared Pool 的主要相关参数:
MEMORY_POOL MEMORY_EXTENT_SIZE MEMORY_TARGET MEMORY_N_POOLS MEMORY_BAK_POOL
Session 相关参数:
SESS_POOL_SIZE SESS_POOL_TARGET
Session 内存可以通过 CREATOR 与 V$SESSIONS.THRD_ID 关联:
SELECT
A.CREATOR,
B.SQL_TEXT,
SUM(A.TOTAL_SIZE) / 1024.0 / 1024.0 AS TOTAL_M,
SUM(A.DATA_SIZE) / 1024.0 / 1024.0 AS DATA_SIZE_M
FROM V$MEM_POOL A
JOIN V$SESSIONS B
ON A.CREATOR = B.THRD_ID
GROUP BY
A.CREATOR,
B.SQL_TEXT
ORDER BY TOTAL_M DESC;
这条查询主要用于回答:
当前哪些会话关联的内存池规模较大?
需要注意,连接数增加不等于内存一定异常,应结合单 Session 内存和整体内存压力判断。
核心视图:
SELECT
NAME,
N_PAGES,
FREE,
N_DISCARD64
FROM V$BUFFERPOOL;
三个核心指标:
| 指标 | 含义 |
|---|---|
N_PAGES |
Buffer 页数 |
FREE |
空闲页数量 |
N_DISCARD64 |
淘汰页数量 |
分析模型:
Buffer │ ├── 容量:N_PAGES ├── 空闲:FREE └── 淘汰:N_DISCARD64
Buffer 的运行状态更应该关注:
FREE 较多 → 可能较空闲 FREE = 0 → 关注是否持续满载 N_DISCARD64 持续增加 → 关注淘汰频率
FREE = 0 或存在淘汰并不自动代表异常。Data Buffer 本身存在正常淘汰机制:
Data Buffer ├── Free Chain ├── LRU Chain └── Dirty Chain
当 Free Chain 不足时,会从 LRU Chain 中选择较少使用的页进行淘汰。
因此真正需要判断的是:
是否因为容量不足导致频繁淘汰,并进一步影响业务访问。
| Buffer | 主要用途 | 相关参数 |
|---|---|---|
| NORMAL | 普通数据页 | BUFFER |
| KEEP | 热点数据页 | KEEP |
| RECYCLE | 临时表、中间结果 | RECYCLE |
| FAST | 快速访问场景 | FAST_POOL_PAGES |
| Log Buffer | REDO 日志缓存 | RLOG_BUF_SIZE、RLOG_POOL_SIZE |
| Dictionary Buffer | 数据字典缓存 | DICT_BUF_SIZE |
| SQL Buffer | SQL/计划相关缓存 | CACHE_POOL_SIZE、USE_PLN_POOL |
其中:
BUFFER_POOLS 将大的共享 Buffer 划分为多个子池:
BUFFER ├── Pool 0 ├── Pool 1 ├── Pool 2 └── Pool 3
其主要目的不是简单增加容量,而是降低高并发访问时的资源竞争。
同理:
MEMORY_N_POOLS → Shared Pool 分片 → 降低并发竞争 BUFFER_POOLS → Buffer 分片 → 降低并发竞争
SQL Runtime 与实例级内存最大的区别是生命周期较短:
Session ↓ SQL ↓ VM / Runtime ├── SORT ├── HASH └── 其他执行过程 ↓ SQL 执行结束 ↓ Runtime 资源释放
资料指出:
因此,SQL Runtime 的关键不是“长期占了多少”,而是:
什么 SQL 在什么执行阶段消耗了多少内存。
V$SQL_STAT 需要开启 SQL 监控后才能开始相关统计。
SELECT
SESSID,
MAX_MEM_USED,
SQL_TXT
FROM V$SQL_STAT
ORDER BY MAX_MEM_USED DESC;
历史 SQL 统计:
SELECT *
FROM V$SQL_STAT_HISTORY;
大内存 SQL 可以进一步结合:
V$SQL_STAT V$SQL_STAT_HISTORY V$LARGE_MEM_SQLS V$GSA
形成:
实例内存异常 ↓ Runtime 增长 ↓ MAX_MEM_USED ↓ 定位 SQL ↓ 分析 SORT / HASH / DISTINCT
典型产生排序内存的场景:
ORDER BY GROUP BY DISTINCT
基本过程:
SQL ↓ 发生排序 ↓ 申请 Runtime Memory ↓ 执行 SORT ↓ 释放 Runtime Memory
相关参数:
SORT_BUF_SIZE
资料建议默认值为 20MB,除非根据实际需求调整。
现场不要直接因为“排序慢”就提高 SORT_BUF_SIZE,应先确认:
SQL ↓ 是否大量 SORT ↓ SQL 内存 ↓ Runtime 行为 ↓ 执行过程 ↓ SORT_BUF_SIZE
DM8 的 HASH 区属于虚拟缓冲区,不应理解为一块始终常驻的固定内存。
典型过程:
HASH JOIN ↓ 计算数据量 ├── 不超过 HJ_BUF_SIZE │ ↓ │ 内存哈希 │ └── 超过 ↓ 外存哈希
相关参数:
HJ_BUF_SIZE
其大小会影响 HASH JOIN 执行效率,应根据实际执行行为调整。
HASH 等运行时对象的资源来源还涉及 VM/MEMOBJ:
HASH ↓ VM ↓ MEMOBJ ↓ VM_MEM_HEAP
资料给出的资源来源关系:
VM_MEM_HEAP ├── 0 → Memory Pool、OS ├── 1 → Heap、Shared Pool └── 2 → Memory Pool + Heap
因此分析 SQL Runtime 时必须区分:
“这块内存用于什么” 与 “这块内存从哪里申请”。
问题现象
OS RES 持续升高 ↓ 需要确认 DM 内部是哪类内存增长
第一步:确认 DM 总体内存
SELECT
(SELECT SUM(N_PAGES * PAGE_SIZE) / 1024 / 1024
FROM V$BUFFERPOOL) AS BUFFER_MB,
(SELECT SUM(TOTAL_SIZE) / 1024 / 1024
FROM V$MEM_POOL) AS MPOOL_MB
FROM DUAL;
第二步:判断增长方向
MPOOL 增长 → 进入 V$MEM_POOL Buffer 增长 → 进入 V$BUFFERPOOL 两者均不明显 → 继续结合 V$SYSSTAT、OS 和具体模块分析
第三步:定位 Pool
SELECT
NAME,
TOTAL_SIZE / 1024 / 1024 AS TOTAL_MB,
RESERVED_SIZE / 1024 / 1024 AS RESERVED_MB,
DATA_SIZE / 1024 / 1024 AS DATA_MB,
TARGET_SIZE,
N_EXTEND_NORMAL,
N_EXTEND_EXCLUSIVE,
IS_OVERFLOW
FROM V$MEM_POOL
ORDER BY TOTAL_SIZE DESC;
第四步:判断是否异常
重点回答:
TOTAL_SIZE 是否超过 TARGET_SIZE?N_EXTEND_EXCLUSIVE 是否持续增加?IS_OVERFLOW?不要把“内存增长”直接等同于“内存泄漏”。
问题现象
TOTAL_SIZE > TARGET_SIZE N_EXTEND_EXCLUSIVE 持续增加
分析路径
具体 Pool ↓ 为什么需要持续扩展? ↓ 业务负载是否持续? ↓ 实际 DATA_SIZE / RESERVED_SIZE ↓ 是否长期超过 Target? ↓ Shared Pool 是否提供池外资源?
建议连续采集:
SELECT
NAME,
TOTAL_SIZE / 1024 / 1024 AS TOTAL_MB,
RESERVED_SIZE / 1024 / 1024 AS RESERVED_MB,
DATA_SIZE / 1024 / 1024 AS DATA_MB,
TARGET_SIZE,
N_EXTEND_NORMAL,
N_EXTEND_EXCLUSIVE
FROM V$MEM_POOL
ORDER BY TOTAL_SIZE DESC;
判断原则
N_EXTEND_EXCLUSIVE 持续增长:重点分析池外扩展原因;问题现象
日志出现:
out of memory, fail to allocate memory from mem pool: BACKUP POOL
排查路径
普通 Pool ↓ Shared Pool ↓ OS ↓ 申请失败 ↓ Backup Pool
首先检查:
SELECT
NAME,
IS_OVERFLOW,
TOTAL_SIZE / 1024 / 1024 AS TOTAL_MB,
RESERVED_SIZE / 1024 / 1024 AS RESERVED_MB,
DATA_SIZE / 1024 / 1024 AS DATA_MB
FROM V$MEM_POOL
WHERE IS_OVERFLOW = 1
ORDER BY TOTAL_SIZE DESC;
同时检查:
OS 剩余内存 DM 总体内存 Shared Pool 具体 Pool 并发 Session SQL Runtime
Backup Pool 是应急资源,不能把“已经使用 Backup Pool”作为正常扩容手段。应继续寻找为什么正常资源不足。
问题现象
Session 数量 ↑ ↓ DM 内存 ↑
不要直接得出“Session 参数太小/太大”的结论。
先关联 Session:
SELECT
A.CREATOR,
B.SQL_TEXT,
SUM(A.TOTAL_SIZE) / 1024.0 / 1024.0 AS TOTAL_M,
SUM(A.DATA_SIZE) / 1024.0 / 1024.0 AS DATA_SIZE_M
FROM V$MEM_POOL A
JOIN V$SESSIONS B
ON A.CREATOR = B.THRD_ID
GROUP BY
A.CREATOR,
B.SQL_TEXT
ORDER BY TOTAL_M DESC;
然后区分:
连接数增加 ├── Session 自身内存增加 ├── SQL Runtime 增加 └── 两者共同增加
相关参数:
SESS_POOL_SIZE SESS_POOL_TARGET
原则:
不要仅根据连接数调整 Session 内存参数,应结合单 Session 实际内存和实例总体内存分析。
适用条件
业务结束 ↓ 内存仍持续增长 ↓ 正常 Pool / Runtime 释放后仍不下降
开启检查:
ALTER SYSTEM SET 'MEMORY_LEAK_CHECK'=1;
查询:
SELECT *
FROM V$MEM_REGINFO
ORDER BY REFNUM DESC;
重点观察:
POOL FNO LINENO REFNUM RESERVED_SIZE DATA_SIZE FNAME ADDR
判断逻辑:
REFNUM 较高 ↓ 持续观察 ↓ 业务结束 ↓ REFNUM / 相关规模下降? ├── 是 → 更符合正常释放 └── 否 → 进一步排查
排查结束后关闭:
ALTER SYSTEM SET 'MEMORY_LEAK_CHECK'=0;
MEMORY_LEAK_CHECK会产生较大性能影响,不建议长期开启。
问题现象
SQL / I/O 压力增加 ↓ 怀疑 Buffer 不足
先查看:
SELECT
NAME,
N_PAGES,
FREE,
N_DISCARD64
FROM V$BUFFERPOOL;
判断:
FREE 较多 → 不支持“Buffer 容量不足”的判断 FREE = 0 → 继续观察 N_DISCARD64 持续增加 → 重点关注淘汰频率
核心原则:
Buffer 有淘汰是机制本身的一部分,只有频繁淘汰并与业务问题相关时,才需要进一步考虑容量。
如果 Buffer 容量本身合理,但高并发访问时存在明显竞争,应考虑:
BUFFER ↓ BUFFER_POOLS ↓ 多个 Buffer 子池
这里要区分:
BUFFER:主要解决容量问题;BUFFER_POOLS:主要解决并发竞争问题。因此:
Buffer 不足与 Buffer 竞争不是同一种问题。
根据资料:
NORMAL → 普通数据页 KEEP → 热点数据页,尽量保留 RECYCLE → 临时表、中间结果,正常淘汰 FAST → 特殊快速访问
分析时首先确认数据访问类型,再考虑是否应该使用相应 Buffer。
不要因为看到某类数据访问频繁,就简单地把更多数据放入 KEEP;也不要把 RECYCLE 理解成“更大的 Buffer”。
SQL Buffer 相关参数:
CACHE_POOL_SIZE USE_PLN_POOL
分析路径:
SQL Cache 增长 ↓ 缓存项增加? ↓ 计划重用情况? ↓ 内存是否持续增长? ↓ 是否形成实例内存压力?
可以结合:
SELECT *
FROM V$CACHEITEM;
进一步分析 SQL 缓冲区缓存项。
问题现象
实例内存突然升高 ↓ Memory Pool / Buffer 无明显异常 ↓ 怀疑 SQL Runtime
首先查看:
SELECT
SESSID,
MAX_MEM_USED,
SQL_TXT
FROM V$SQL_STAT
ORDER BY MAX_MEM_USED DESC;
如需历史信息:
SELECT *
FROM V$SQL_STAT_HISTORY;
分析:
MAX_MEM_USED ↓ 定位 SQL ↓ 判断执行过程 ├── SORT ├── HASH ├── DISTINCT └── 其他 Runtime
典型 SQL:
ORDER BY
GROUP BY
DISTINCT
排查:
SQL ↓ 是否产生大量 SORT ↓ MAX_MEM_USED ↓ SORT Runtime ↓ SORT_BUF_SIZE
相关参数:
SORT_BUF_SIZE
处理原则:
SORT_BUF_SIZE;不要仅依据“排序慢”直接放大排序缓冲区。
分析模型:
HASH JOIN ↓ 数据量 ↓ HJ_BUF_SIZE ├── 可在内存中完成 └── 超出后使用外存哈希
相关参数:
HJ_BUF_SIZE
注意:
HJ_BUF_SIZE对应的是 HASH JOIN 执行行为,不能简单理解为一块始终常驻的固定内存。
因此应结合具体 SQL、数据量和执行行为判断。
当发现 SQL Runtime 内存较大时,还要回答:
这块内存属于什么? ↓ SORT / HASH / VM? ↓ 从哪里申请?
对于 VM/MEMOBJ,可以结合:
VM_MEM_HEAP
分析其资源来源:
0 → Memory Pool、OS 1 → Heap、Shared Pool 2 → Memory Pool + Heap
因此 SQL Runtime 排查不能把“用途”和“来源”混为一谈。
无论遇到哪一种 DM8 内存问题,都建议统一使用以下路径:
发现现象 ↓ ① OS 内存 ↓ ② DM 总体内存 ↓ ③ MPOLL / Buffer ↓ ④ 具体 Pool / Buffer ↓ ⑤ 扩展、Target、淘汰 ↓ ⑥ Session / SQL Runtime ↓ ⑦ 参数与资源来源 ↓ ⑧ 判断原因 ↓ ⑨ 处理 ↓ ⑩ 验证
Linux:
free -h top
关注:
物理内存 Swap DM Server RES / VIRT
SELECT
(SELECT SUM(N_PAGES * PAGE_SIZE) / 1024 / 1024
FROM V$BUFFERPOOL) AS BUFFER_MB,
(SELECT SUM(TOTAL_SIZE) / 1024 / 1024
FROM V$MEM_POOL) AS MPOOL_MB
FROM DUAL;
先判断:
Buffer 增长? Memory Pool 增长? 还是两者都有?
SELECT
NAME,
TOTAL_SIZE / 1024 / 1024 AS TOTAL_MB,
RESERVED_SIZE / 1024 / 1024 AS RESERVED_MB,
DATA_SIZE / 1024 / 1024 AS DATA_MB,
TARGET_SIZE,
N_EXTEND_NORMAL,
N_EXTEND_EXCLUSIVE,
IS_OVERFLOW
FROM V$MEM_POOL
ORDER BY TOTAL_SIZE DESC;
重点:
谁最大? 谁在增长? 谁超过 Target? 谁发生 Exclusive Extend? 谁使用 Backup Pool?
SELECT
NAME,
N_PAGES,
FREE,
N_DISCARD64
FROM V$BUFFERPOOL;
重点:
容量 ↓ FREE ↓ 淘汰 ↓ 淘汰是否持续增加
Session:
SELECT
A.CREATOR,
B.SQL_TEXT,
SUM(A.TOTAL_SIZE) / 1024.0 / 1024.0 AS TOTAL_M,
SUM(A.DATA_SIZE) / 1024.0 / 1024.0 AS DATA_SIZE_M
FROM V$MEM_POOL A
JOIN V$SESSIONS B
ON A.CREATOR = B.THRD_ID
GROUP BY
A.CREATOR,
B.SQL_TEXT
ORDER BY TOTAL_M DESC;
SQL:
SELECT
SESSID,
MAX_MEM_USED,
SQL_TXT
FROM V$SQL_STAT
ORDER BY MAX_MEM_USED DESC;
系统统计:
SELECT
NAME,
STAT_VAL / 1024.0 / 1024.0 AS STAT_MB
FROM V$SYSSTAT
WHERE CLASSID = 11;
重点指标:
| 指标 | 含义 |
|---|---|
memory pool size in bytes |
内存池总大小 |
memory used bytes |
内存池使用大小 |
memory used bytes from os |
从 OS 分配的大小 |
怀疑泄漏时再使用:
ALTER SYSTEM SET 'MEMORY_LEAK_CHECK'=1;
SELECT *
FROM V$MEM_REGINFO
ORDER BY REFNUM DESC;
ALTER SYSTEM SET 'MEMORY_LEAK_CHECK'=0;
参数调整不应独立进行,而应建立:参数+运行状态+业务负载+OS 资源
核心参数可按三个对象记忆:
| 对象 | 主要参数 |
|---|---|
| MPOLL | MEMORY_POOL、MEMORY_EXTENT_SIZE、MEMORY_TARGET、MEMORY_N_POOLS、MEMORY_BAK_POOL |
| Buffer | BUFFER、BUFFER_POOLS、KEEP、RECYCLE、FAST_POOL_PAGES |
| SQL Runtime | SORT_BUF_SIZE、HJ_BUF_SIZE、VM_MEM_HEAP |
其他常用参数:
MAX_OS_MEMORY SESS_POOL_SIZE SESS_POOL_TARGET VM_POOL_SIZE VM_POOL_TARGET DICT_BUF_SIZE CACHE_POOL_SIZE USE_PLN_POOL RLOG_BUF_SIZE RLOG_POOL_SIZE
统一原则:
现象 ↓ 定位 ↓ 确认对象 ↓ 确认运行行为 ↓ 分析参数 ↓ 调整 ↓ 重新运行负载 ↓ 重新监控 ↓ 验证结果
不要因为看到某个参数值较小,就直接认定它是问题根因。
文章
阅读量
获赞
