ORA-00018根本原因是PROCESSES槽位耗尽,而非单纯连接数超限;需优先查v$process与参数对比,重点清理J000卡死作业、残留后台进程及空闲超时未提交事务会话。

ORA-00018 报错时,根本不是“连接数太多”,而是“槽位被占满”
Oracle 的 SESSIONS 不是独立资源池,它依赖 PROCESSES 分配底层 OS 进程槽位。一旦 PROCESSES 耗尽,哪怕 SESSIONS 还有余量,新会话也会直接报 ORA-00018。常见诱因不是用户猛增,而是以下几类“不释放槽位”的行为:
- Java 应用未正确关闭
Connection,连接池配置了 maxActive=50 但 minIdle=0,空闲连接被回收后又重建,反复占用新 process 槽位 - DBA 在服务器本地开了多个
sqlplus / as sysdba终端却没退出,每个终端独占一个后台进程(process),且不会计入v$session的普通用户统计 - 数据库作业(
DBMS_SCHEDULER)卡住,状态为KILLED或FAILED,但对应进程仍在v$process中残留,无法自动清理
查 v$process 比查 v$session 更准,尤其当看到 PROGRAM 是 oracle@host (J000) 或 ora_pmon_
v$session 显示的是逻辑会话,v$process 才反映真实 OS 进程占用。当 ORA-00018 突发,优先执行:
SELECT COUNT(*) FROM v$process;
再对比 SHOW PARAMETER PROCESSES。如果两者接近(比如差 ≤5),基本锁定是 PROCESSES 被耗尽。此时重点筛 v$process 中的异常 PROGRAM:
-
oracle@host (J000):调度器 job slave 卡死,需查dba_scheduler_jobs状态 -
ora_pmon_、ora_mman_等后台进程数量异常多:可能是实例未完全启动或崩溃后残留 -
oracle@host (DESCRIPTION=...):典型 JDBC Thin Client,但SPID相同的多个条目说明连接复用失败,应用层在反复新建连接
别信“inactive 就该杀”,INACTIVE 会话本身不占 PROCESSES 槽位,但可能掩盖事务未提交
v$session.STATUS = 'INACTIVE' 只表示当前没在执行 SQL,不代表安全可杀。真正危险的是:STATUS = 'INACTIVE' 但 SQL_ID IS NULL 且 LAST_CALL_ET > 3600(空闲超一小时)——这往往意味着程序拿到连接后没 commit 或 rollback,事务仍持有锁和 PGA 内存,对应 v$process 槽位也无法释放。
验证方法:
SELECT sid, serial#, username, sql_id, last_call_et, event FROM v$session WHERE status = 'INACTIVE' AND last_call_et > 3600 AND sql_id IS NULL;
这类会话若确认无业务影响,可用 ALTER SYSTEM KILL SESSION 'sid,serial#' IMMEDIATE 强制释放;否则应联系应用方检查事务边界。
SQLNET.EXPIRE_TIME 和 IDLE_TIME 都不解决根本问题,只是兜底
设 SQLNET.EXPIRE_TIME=10(sqlnet.ora)会让服务端每 10 分钟发探测包,断开僵死网络连接;设 ALTER PROFILE DEFAULT LIMIT IDLE_TIME 10 是让会话空闲 10 分钟后自动断开。但这两者都依赖客户端响应或 profile 生效前提——如果应用用的是连接池且配置了 testOnBorrow=false,这些机制就形同虚设。
更可靠的做法是:在连接池层面强制校验,例如 HikariCP 的 connection-test-query=SELECT 1 FROM DUAL + validation-timeout=3000,确保每次借出连接前真能连通并及时发现失效连接。
真正容易被忽略的点是:PROCESSES 调高后必须同步调高 OS 层 ulimit -u,否则实例重启会卡在 “starting background processes”,连 sqlplus / as sysdba 都进不去。这个检查常被跳过,直到重启失败才返工。


















