ORA-04031错误主因常是共享池中Java类元数据未卸载,而非JAVA_POOL_SIZE不足;需启用_java_class_unload=TRUE并监控v$sgastat中java相关chunk,而非盲目调大JAVA_POOL_SIZE。
ORA-04031 错误出现时,JAVA_POOL_SIZE 真的是主因?
不是所有 ora-04031: unable to allocate <em>bytes</em> of shared memory 都该调大 java_pool_size。oracle jvm 的类加载行为和共享池(shared_pool)资源竞争更常被忽略。
典型误判场景:应用频繁部署 Java 存储过程、调用 DBMS_JAVA 加载新 JAR,但 DBA 只盯着 JAVA_POOL_SIZE 一路加到 1G+,仍反复报错——问题其实在类未卸载,残留的 java.lang.Class 元数据卡在共享池里。
-
JAVA_POOL主要存放 JVM 运行时结构(如方法区、JIT 缓存),不存类定义元数据;后者实际放在SHARED_POOL - 每次
loadjava或动态加载类,都会在共享池生成LOADJAVA_*和CLASS$-related chunks - Oracle 11g+ 默认关闭类卸载(
_java_class_unload隐含参数为FALSE),即使类不再使用也不会释放
检查类是否真被卸载:别只看 V$JAVA_POOL
V$JAVA_POOL 显示的是 JVM 堆内内存使用,对诊断类泄漏几乎无用。真正关键的是共享池中 Java 相关对象的占用情况。
执行以下查询确认类残留:
SELECT pool, name, bytes/1024/1024 MB FROM v$sgastat WHERE pool = 'shared pool' AND name LIKE '%java%' ORDER BY bytes DESC;
若看到大量 LOADJAVA_* 或 CLASS$ 条目且 MB 数持续增长,说明类没卸载。
立即学习“Java免费学习笔记(深入)”;
- 必须启用隐含参数
_java_class_unload=TRUE(需重启实例),否则dropjava或重载 JAR 不会清理旧类元数据 -
ALTER SYSTEM FLUSH SHARED_POOL会清掉,但属暴力手段,影响全局性能,不能作为常规方案 - 12c+ 推荐改用
DBMS_JAVA.UNLOAD_CLASS显式卸载指定类,比依赖自动卸载更可控
JAVA_POOL_SIZE 调整的合理范围与副作用
盲目增大 JAVA_POOL_SIZE 不仅无效,还可能挤占 SHARED_POOL 或 LARGE_POOL,引发其他 ORA-4031 变体。
经验值参考(基于 16GB SGA 总量):
- 纯 PL/SQL 调用 Java(无
loadjava):JAVA_POOL_SIZE设为 64M–128M 足够 - 高频部署 JAR(如每日多次
loadjava -force):需配合_java_class_unload=TRUE,JAVA_POOL_SIZE保持 256M 内即可 - 设超过 512M 后,SGA 分配碎片化风险陡增,尤其在 AIX 或旧 Linux 内核上易触发
ORA-27102: out of memory
调整后务必监控 V$SGASTAT 中 java pool 的 free memory 是否稳定,而非只看“已用”值。
类加载器隔离不足导致的隐性泄漏
Oracle JVM 默认使用单 ClassLoader(OracleClassLoader),所有用户加载的类共享同一命名空间。一个用户的 loadjava 可能污染另一个用户的类缓存。
常见症状:A 用户 dropjava 后,B 用户调用同名类仍失败,或报 ClassNotFoundException 却查不到对应 JAR。
- 避免跨用户共用 Java 类:用
CREATE JAVA SCHEMA或按用户分 JAR 包名前缀 - 慎用
loadjava -r(resolve):它会强制解析所有依赖,把间接引用的类也拉进共享池,扩大泄漏面 - 调试时可用
DBMS_JAVA.LONGNAME查具体类的完整内部名,确认是否重复加载
类卸载不是开关一开就自动干净的事——它依赖显式卸载动作、ClassLoader 边界清晰、以及共享池本身没被其他对象(比如 SQL Area)长期 pin 住。漏掉任一环,JAVA_POOL_SIZE 调再大也只是给错误腾地方。










