PL/SQL集合的DELETE方法不释放PGA内存,仅重置逻辑结构;真正释放需显式赋NULL或在新作用域重新声明变量,否则循环中反复DELETE+EXTEND将导致PGA持续增长乃至ORA-04030错误。
PL/SQL集合的DELETE方法不释放PGA内存
调用 delete 方法清空 pl/sql 集合(如 index by table 或 nested table)后,集合变量仍占用原有 pga 内存 —— 这不是 bug,是 oracle 的设计行为。oracle 只在集合变量超出作用域(比如过程退出)或被显式赋值为 null 时才真正释放底层内存块。
-
DELETE仅重置集合的逻辑结构(COUNT=0、FIRST/LAST返回NULL),但底层分配的内存块不会归还给 PGA heap - 反复
DELETE+EXTEND同一个集合变量,会导致 PGA 持续增长,可能触发ORA-04030: out of process memory - 对大对象(如
VARCHAR2(32767)字段组成的万级记录集合),这种“假清空”尤其危险
真正释放集合内存的两种可靠方式
要让 Oracle 立即回收集合所占 PGA,必须打破变量与内存块的绑定关系:
- 显式赋值为
NULL:my_collection := NULL;—— 最直接,适用于所有集合类型 - 重新声明同名变量(在新作用域内):
DECLARE my_collection my_type; BEGIN ... END;—— 原变量随作用域结束自动释放 - 避免误用
TRIM或DELETE(n):它们只删元素,不碰内存分配器
批量处理中集合内存泄漏的典型场景
在循环中反复填充、处理、清空同一集合变量,是 PGA 泄漏高发区:
- 错误写法:
LOOP collection.DELETE; collection.EXTEND; ... END LOOP;→ PGA 持续膨胀 - 正确写法:
LOOP collection := NULL; collection := my_type(); ... END LOOP;→ 每次都新建干净内存块 - 更优写法:把集合声明移到循环内部,让每次迭代拥有独立作用域,无需手动干预
验证内存是否真正释放
不能只看 COUNT,得查 V$PROCESS_MEMORY 或用 DBMS_SESSION 监控:
- 执行前:
SELECT name, bytes FROM V$PROCESS_MEMORY WHERE pid = (SELECT pid FROM V$SESSION WHERE sid = SYS_CONTEXT('USERENV','SID')) AND name LIKE '%PL/SQL%'; - 执行
collection := NULL;后再查,对应项应明显下降 -
DBMS_OUTPUT.PUT_LINE('PGA used: ' || TO_CHAR(V$PROCESS_MEMORY.bytes));不可用 —— 这个视图无法在 PL/SQL 块内直接查,需外部会话配合
DELETE 后悄悄回收,它只认变量生命周期和显式赋值。忽略这点,跑几小时的批处理就可能因 PGA 耗尽而中断。











