显式游标未释放会导致会话级pga内存和游标句柄持续占用,且不随pl/sql块退出自动清理;必须在异常处理中用%isopen判断后close,包级ref cursor需在包内关闭,验证须查v$open_cursor。

显式游标未释放会直接占用会话级 PGA 内存和游标句柄,且不会随 PL/SQL 块退出自动清理
OPEN 后不 CLOSE,游标槽位和内存都卡死在会话里
Oracle 显式游标一旦 OPEN,就立即在当前会话的 open_cursors 槽位中注册一个条目,并从 PGA 分配内存用于缓存结果集元数据、绑定信息和部分 fetched 数据。这个槽位和内存**不会因为 PL/SQL 块执行结束而释放**——只有整个会话断开时,Oracle 才做兜底回收,但不可依赖。
-
V$OPEN_CURSOR里能看到该游标持续存在,last_sql_time长期不更新 - 同一会话反复调用含
OPEN的过程,opened cursors current统计值持续上涨 - PGA 使用量(查
v$pgastat)同步增长,尤其当游标带BULK COLLECT时更明显
异常路径漏掉 CLOSE 是最常见泄漏源头
很多人只在正常流程末尾写 CLOSE cursor_name,但一旦 FETCH 过程中抛出 NO_DATA_FOUND 以外的异常(如 ORA-01403、网络中断、权限变更),控制流直接跳进 EXCEPTION 块,CLOSE 就被跳过了。
- 错误写法:
END; CLOSE c1;——RETURN或异常都会绕过它 - 正确写法:必须在
EXCEPTION中加IF c1%ISOPEN THEN CLOSE c1; - 重复
CLOSE会报ORA-01001: invalid cursor,所以用%ISOPEN判断是安全底线
包级 REF CURSOR 是隐蔽的“长周期”泄漏点
把 SYS_REFCURSOR 声明为包变量(PACKAGE 级),再在过程里 OPEN 赋值,相当于把游标生命周期延长到整个会话。连接池环境下,这个物理连接被复用多次,包变量里的游标可能被反复 OPEN 却从不 CLOSE。
-
V$OPEN_CURSOR中会出现 sql_text 相同但sql_id不同的多条记录(说明未复用) -
V$SESSION查到该会话的prev_sql_id长期没变,status为 ACTIVE,但实际业务已空闲 - 包内声明的游标变量,
CLOSE必须在包内完成,过程里CLOSE对包变量无效
别信日志,一定要查 V$OPEN_CURSOR 实时验证
代码里写了 CLOSE ≠ 游标真关了。驱动层缓存、REF CURSOR 被传出到应用层、或 DBMS_SQL 动态游标未显式关闭,都可能导致 CLOSE 失效。唯一可信的方式是登录数据库查视图:
SELECT sql_id, sql_text, last_sql_time FROM v$open_cursor WHERE sid = <your_sid> ORDER BY last_sql_time DESC;</your_sid>
重点看是否有大量重复 sql_text、last_sql_time 几小时没动、或 sql_id 完全不复用——这些都不是配置调参能掩盖的问题,得改代码。











