dbms_shared_pool.purge 默认只清理库缓存句柄而不释放内存堆,需指定heaps参数(如64)才能彻底清除pl/sql对象;若对象被keep锁定,则purge静默失败,须先unkeep;多租户下需切换容器且权限受限。
dbms_shared_pool.purge 为什么执行后对象还在共享池里
根本原因不是没执行成功,而是 purge 默认只清理「库缓存句柄」(handle),不释放底层的「内存堆」(heap)。尤其对包、过程这类 pl/sql 对象,必须显式指定 heaps 参数才能真正清掉代码段和符号表。
- 正确写法是:
DBMS_SHARED_POOL.PURGE('SCHEMA.PACKAGE_NAME', 'P', 64)—— 注意第三个参数64表示清除所有堆(包括 heap 0~6) - 常见错误:漏掉第三个参数,或传
1(只清 handle),结果V$DB_OBJECT_CACHE里仍显示KEPT = 'YES' - 对象名必须带 schema,比如
'HR.EMP_PKG';大小写敏感,且不能加引号(除非创建时用了双引号) - 执行前确认用户有
EXECUTE权限 onDBMS_SHARED_POOL,否则报ORA-01031: insufficient privileges
DBMS_SHARED_POOL.KEEP 导致后续 PURGE 失效怎么办
KEEP 是硬锁定,只要没显式调用 UNKEEP,PURGE 就会静默失败——不会报错,但对象纹丝不动。这是最常被忽略的“假成功”场景。
- 先查是否被 keep:
SELECT name, type, kept FROM v$db_object_cache WHERE kept = 'YES' AND name LIKE '%YOUR_OBJ%' - 解除锁定必须用
DBMS_SHARED_POOL.UNKEEP,参数格式和KEEP完全一致,比如UNKEEP('SCHEMA.PACKAGE_NAME', 'P') - 注意:
UNKEEP不校验对象是否存在,输错名也不会报错,得靠查V$DB_OBJECT_CACHE确认是否真解除了 - 如果不确定哪些被 keep 过,别盲目 purge,先跑一遍
SELECT * FROM v$db_object_cache WHERE kept = 'YES'
刷新 PACKAGE 后遇到 ORA-04068/ORA-04061 怎么办
这不是共享池清理问题,而是 PL/SQL 的依赖失效机制在起作用。即使你 purge 了包体,调用方 session 里已加载的包状态(state)可能还残留着旧版本符号,导致运行时报错。
- 单纯 purge 包体(
'P')不够,必须连同包规范('PK')一起清,或者直接清整个 package 名(不区分 spec/body) - 更稳妥的做法:先
ALTER PACKAGE xxx COMPILE,再PURGE,避免中间状态不一致 - 客户端 session 需要重新执行
EXECUTE IMMEDIATE 'BEGIN NULL; END;'或调用任意新编译过的子程序,才能触发内部 reload - 批量刷新时,顺序很重要:先 spec,再 body;如果 body 依赖其他未编译的包,
COMPILE会失败,PURGE也救不了
DBMS_SHARED_POOL 在 12c+ 多租户环境下的权限坑
在 CDB 中,DBMS_SHARED_POOL 默认只能操作当前 PDB 的共享池。如果你 connect 到 CDB$ROOT 并试图 purge 某个 PDB 的对象,操作会静默跳过——既不报错,也不生效。
- 必须先
ALTER SESSION SET CONTAINER = pdb_name,再执行 purge/keep - CDB 级管理员想批量操作多个 PDB,得用
DBMS_CLOUD_ADMIN或写 loop 切 container,不能指望一条命令扫全库 - 19c 起,
V$DB_OBJECT_CACHE在 CDB 视图里默认只返回当前 container 数据,跨 PDB 查要连CDB_*视图(如CDB_DB_OBJECT_CACHE),但该视图不含KEPT字段 - 权限上,PDB_DBA 角色才够用;CDB_DBA 在 root 下没有 PDB 内部对象的操作权
真正麻烦的从来不是怎么 purge,而是 purge 之后谁还记得自己曾经 keep 过、在哪一版 PDB 里、有没有人正在跑着那个包——这些信息散落在不同视图、不同容器、不同 session 里,查漏成本远高于执行成本。










