注册
DM内存管理与实践
培训园地/ 文章详情 /

DM内存管理与实践

DM_052010 2026/08/25 173 0 0

DM8 内存管理与实践

本文将 DM8 内存问题统一归入三个分析对象:

  • MPOLL(Memory Pool):关注池规模、使用、扩展、Target、Backup Pool 以及资源来源。
  • Buffer:关注缓冲区规模、空闲页和淘汰行为。
  • SQL Runtime:关注 Session/VM 运行时内存,以及 SORT、HASH 等 SQL 执行过程的内存消耗。

一、DM8 内存监控

1.1 MPOLL:Memory Pool 监控

1.1.1 DM 总体内存

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增长。

1.1.2 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 说明发生过超过目标规模的扩展,但扩展本身不等于异常。需要结合持续时间、业务负载以及释放情况判断。

1.1.3 观察 Pool 的“行为”

Memory Pool 的基本运行过程:

Original Size ↓ 正常使用 ↓ 空间不足 ↓ 扩展 ↓ 达到 Target ↓ 仍可继续扩展 ↓ 对象释放 ↓ 超出 Target 的部分可释放

因此:

  • RESERVED_SIZE 明显小于初始规模:可以作为池较空闲的观察信号;
  • TOTAL_SIZE 长期高于 TARGET_SIZE:关注池外扩展;
  • N_EXTEND_EXCLUSIVE 持续增长:分析为什么长期超过 Target;
  • IS_OVERFLOW 表示使用了备用资源,需要重点关注。

技术指导资料强调应尽量保持各内存池自持,减少池外分配。

1.1.4 继续追踪资源来源

现场不能只停留在“哪个 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。

1.1.5 监控共享池与 Session

Shared Pool 的主要相关参数:

MEMORY_POOL MEMORY_EXTENT_SIZE MEMORY_TARGET MEMORY_N_POOLS MEMORY_BAK_POOL

Session 相关参数:

SESS_POOL_SIZE SESS_POOL_TARGET

Session 内存可以通过 CREATORV$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 内存和整体内存压力判断。


1.2 Buffer:缓冲区监控

1.2.1 查看 Buffer 总体状态

核心视图:

SELECT NAME, N_PAGES, FREE, N_DISCARD64 FROM V$BUFFERPOOL;

三个核心指标:

指标 含义
N_PAGES Buffer 页数
FREE 空闲页数量
N_DISCARD64 淘汰页数量

分析模型:

Buffer │ ├── 容量:N_PAGES ├── 空闲:FREE └── 淘汰:N_DISCARD64

1.2.2 Buffer 不只看“用了多少”

Buffer 的运行状态更应该关注:

FREE 较多 → 可能较空闲 FREE = 0 → 关注是否持续满载 N_DISCARD64 持续增加 → 关注淘汰频率

FREE = 0 或存在淘汰并不自动代表异常。Data Buffer 本身存在正常淘汰机制:

Data Buffer ├── Free Chain ├── LRU Chain └── Dirty Chain

当 Free Chain 不足时,会从 LRU Chain 中选择较少使用的页进行淘汰。

因此真正需要判断的是:

是否因为容量不足导致频繁淘汰,并进一步影响业务访问。

1.2.3 Buffer 类型与参数

Buffer 主要用途 相关参数
NORMAL 普通数据页 BUFFER
KEEP 热点数据页 KEEP
RECYCLE 临时表、中间结果 RECYCLE
FAST 快速访问场景 FAST_POOL_PAGES
Log Buffer REDO 日志缓存 RLOG_BUF_SIZERLOG_POOL_SIZE
Dictionary Buffer 数据字典缓存 DICT_BUF_SIZE
SQL Buffer SQL/计划相关缓存 CACHE_POOL_SIZEUSE_PLN_POOL

其中:

  • NORMAL 是默认数据缓冲区;
  • KEEP 用于尽量保留热点数据;
  • RECYCLE 主要用于临时表数据页、中间结果集;
  • FAST 从 BUFFER 中划分数据页,不能超过 BUFFER 一半;
  • KEEP 不参与一般淘汰机制。

1.2.4 Buffer 分片

BUFFER_POOLS 将大的共享 Buffer 划分为多个子池:

BUFFER ├── Pool 0 ├── Pool 1 ├── Pool 2 └── Pool 3

其主要目的不是简单增加容量,而是降低高并发访问时的资源竞争。

同理:

MEMORY_N_POOLS → Shared Pool 分片 → 降低并发竞争 BUFFER_POOLS → Buffer 分片 → 降低并发竞争

1.3 SQL Runtime:运行时内存监控

1.3.1 SQL Runtime 的生命周期

SQL Runtime 与实例级内存最大的区别是生命周期较短

Session ↓ SQL ↓ VM / Runtime ├── SORT ├── HASH └── 其他执行过程 ↓ SQL 执行结束 ↓ Runtime 资源释放

资料指出:

  • Session Pool 在连接时创建、断开时销毁;
  • VM 在需要执行 SQL 时创建,SQL 执行完成后销毁;
  • SORT 等运行时内存通常随操作产生并在操作结束后释放。

因此,SQL Runtime 的关键不是“长期占了多少”,而是:

什么 SQL 在什么执行阶段消耗了多少内存。

1.3.2 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

1.3.3 SORT

典型产生排序内存的场景:

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

1.3.4 HASH

DM8 的 HASH 区属于虚拟缓冲区,不应理解为一块始终常驻的固定内存。

典型过程:

HASH JOIN ↓ 计算数据量 ├── 不超过 HJ_BUF_SIZE │ ↓ │ 内存哈希 │ └── 超过 ↓ 外存哈希

相关参数:

HJ_BUF_SIZE

其大小会影响 HASH JOIN 执行效率,应根据实际执行行为调整。

1.3.5 VM_MEM_HEAP:用途与来源分开看

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 时必须区分:

“这块内存用于什么”“这块内存从哪里申请”


二、DM8 内存场景

2.1 MPOLL:Memory Pool 场景

2.1.1 场景:实例内存持续升高

问题现象

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;

第四步:判断是否异常

重点回答:

  1. 哪个 Pool 在增长?
  2. TOTAL_SIZE 是否超过 TARGET_SIZE
  3. N_EXTEND_EXCLUSIVE 是否持续增加?
  4. 是否出现 IS_OVERFLOW
  5. 业务高峰结束后,规模是否回落?

不要把“内存增长”直接等同于“内存泄漏”。


2.1.2 场景:Memory Pool 长期超过 Target

问题现象

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;

判断原则

  • 单次超过 Target:可能只是业务峰值;
  • 长期超过 Target:分析 Target 是否偏小;
  • N_EXTEND_EXCLUSIVE 持续增长:重点分析池外扩展原因;
  • 业务结束后仍持续增长:继续排查具体对象和资源释放。

2.1.3 场景:Backup Pool 被使用

问题现象

日志出现:

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”作为正常扩容手段。应继续寻找为什么正常资源不足。


2.1.4 场景:高并发 Session 导致内存升高

问题现象

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 实际内存和实例总体内存分析。


2.1.5 场景:疑似内存泄漏

适用条件

业务结束 ↓ 内存仍持续增长 ↓ 正常 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 会产生较大性能影响,不建议长期开启。


2.2 Buffer:缓冲区场景

2.2.1 场景:Buffer 频繁淘汰

问题现象

SQL / I/O 压力增加 ↓ 怀疑 Buffer 不足

先查看:

SELECT NAME, N_PAGES, FREE, N_DISCARD64 FROM V$BUFFERPOOL;

判断:

FREE 较多 → 不支持“Buffer 容量不足”的判断 FREE = 0 → 继续观察 N_DISCARD64 持续增加 → 重点关注淘汰频率

核心原则:

Buffer 有淘汰是机制本身的一部分,只有频繁淘汰并与业务问题相关时,才需要进一步考虑容量。


2.2.2 场景:高并发 Buffer 竞争

如果 Buffer 容量本身合理,但高并发访问时存在明显竞争,应考虑:

BUFFER ↓ BUFFER_POOLS ↓ 多个 Buffer 子池

这里要区分:

  • BUFFER:主要解决容量问题;
  • BUFFER_POOLS:主要解决并发竞争问题。

因此:

Buffer 不足与 Buffer 竞争不是同一种问题。


2.2.3 场景:KEEP / RECYCLE 使用不合理

根据资料:

NORMAL → 普通数据页 KEEP → 热点数据页,尽量保留 RECYCLE → 临时表、中间结果,正常淘汰 FAST → 特殊快速访问

分析时首先确认数据访问类型,再考虑是否应该使用相应 Buffer。

不要因为看到某类数据访问频繁,就简单地把更多数据放入 KEEP;也不要把 RECYCLE 理解成“更大的 Buffer”。


2.2.4 场景:SQL Cache 持续增长

SQL Buffer 相关参数:

CACHE_POOL_SIZE USE_PLN_POOL

分析路径:

SQL Cache 增长 ↓ 缓存项增加? ↓ 计划重用情况? ↓ 内存是否持续增长? ↓ 是否形成实例内存压力?

可以结合:

SELECT * FROM V$CACHEITEM;

进一步分析 SQL 缓冲区缓存项。


2.3 SQL Runtime:SQL 执行内存场景

2.3.1 场景:大内存 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

2.3.2 场景:SORT 导致 SQL 内存升高

典型 SQL:

ORDER BY GROUP BY DISTINCT

排查:

SQL ↓ 是否产生大量 SORT ↓ MAX_MEM_USED ↓ SORT Runtime ↓ SORT_BUF_SIZE

相关参数:

SORT_BUF_SIZE

处理原则:

  1. 先定位具体 SQL;
  2. 确认 SORT 是否是主要内存消耗;
  3. 观察实际 Runtime 行为;
  4. 再决定是否调整 SORT_BUF_SIZE
  5. 调整后重新监控。

不要仅依据“排序慢”直接放大排序缓冲区。


2.3.3 场景:HASH JOIN 导致 Runtime 内存增加

分析模型:

HASH JOIN ↓ 数据量 ↓ HJ_BUF_SIZE ├── 可在内存中完成 └── 超出后使用外存哈希

相关参数:

HJ_BUF_SIZE

注意:

HJ_BUF_SIZE 对应的是 HASH JOIN 执行行为,不能简单理解为一块始终常驻的固定内存。

因此应结合具体 SQL、数据量和执行行为判断。


2.3.4 场景:Runtime 内存来源异常

当发现 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 ↓ ⑦ 参数与资源来源 ↓ ⑧ 判断原因 ↓ ⑨ 处理 ↓ ⑩ 验证

3.1 第一层:OS

Linux:

free -h top

关注:

物理内存 Swap DM Server RES / VIRT

3.2 第二层: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;

先判断:

Buffer 增长? Memory Pool 增长? 还是两者都有?

3.3 第三层:MPOLL

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?

3.4 第四层:Buffer

SELECT NAME, N_PAGES, FREE, N_DISCARD64 FROM V$BUFFERPOOL;

重点:

容量 ↓ FREE ↓ 淘汰 ↓ 淘汰是否持续增加

3.5 第五层:Session / SQL Runtime

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;

3.6 第六层:系统统计与泄漏排查

系统统计:

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_POOLMEMORY_EXTENT_SIZEMEMORY_TARGETMEMORY_N_POOLSMEMORY_BAK_POOL
Buffer BUFFERBUFFER_POOLSKEEPRECYCLEFAST_POOL_PAGES
SQL Runtime SORT_BUF_SIZEHJ_BUF_SIZEVM_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

统一原则:

现象 ↓ 定位 ↓ 确认对象 ↓ 确认运行行为 ↓ 分析参数 ↓ 调整 ↓ 重新运行负载 ↓ 重新监控 ↓ 验证结果

不要因为看到某个参数值较小,就直接认定它是问题根因。

评论
后发表回复

作者

文章

阅读量

获赞

扫一扫
联系客服