OCI中LOB定位符必须用OCIDescriptorFree()释放,不能用OCIHandleFree();因后者不清理locator内部状态和关联资源,仅OCIDescriptorFree(locp, OCI_DTYPE_LOB)才能彻底释放底层结构。

OCI中LOB定位符必须用OCIDescriptorFree()释放,不能用OCIHandleFree()
很多人在OCI编程里把OCILobLocator*当成普通句柄,调用OCIHandleFree()释放,结果导致内存持续增长——因为OCIHandleFree()不处理LOB描述符内部的locator状态和关联资源。只有OCIDescriptorFree()才真正清理locator指向的底层结构。
-
OCIDescriptorAlloc()分配的OCI_DTYPE_LOB类型描述符,必须配对使用OCIDescriptorFree(locp, OCI_DTYPE_LOB) - 释放前确保该locator未被任何未完成的LOB操作(如
OCILobWrite()、OCILobRead())引用,否则可能触发ORA-22275或段错误 - 如果程序中途异常退出(比如
longjmp或信号中断),需在cleanup handler中显式调用OCIDescriptorFree(),不能依赖栈展开
Java JDBC里CLOB流未关闭会同时泄漏LOB locator和游标
调用rs.getClob("col").getCharacterStream()后若没关流,不只是流对象泄漏:Oracle JDBC驱动内部用当前游标维护该CLOB的locator生命周期,游标不关闭 → locator不释放 → 下一次fetch可能复用旧locator但状态错乱 → 出现ORA-01002 “fetch out of sequence”或静默数据截断。
- 必须用
try-with-resources包裹getCharacterStream()返回的Reader,而不是只关ResultSet或Statement - 禁用
getClob().getSubString()和toString(),它们绕过流机制,强制全量加载进JVM堆,极易OOM - Spring JdbcTemplate等封装默认不自动关CLOB流,需手动处理或升级到6.1+并启用
spring.jdbc.lob-streaming=true
PL/SQL中REF CURSOR打开后未FETCH完就CLOSE,LOB locator仍残留
当REF CURSOR查询包含CLOB/BLOB列时,即使你显式执行了CLOSE c1,只要之前FETCH过含LOB的行且没消费完对应DBMS_LOB资源,locator仍挂在会话PGA里。典型表现是V$SESSION_LONGOPS里出现大量“LOB READ”条目,且V$TEMPSEG_USAGE中临时段持续增长。
- 必须在
CLOSE前确保所有LOB列都已通过DBMS_LOB.FREETEMPORARY()或完整读取释放(对临时LOB) - 对持久LOB,FETCH后若不再需要内容,应立即调用
DBMS_LOB.CLOSE()(注意不是FREE) - 避免在循环FETCH中反复
OPEN/CLOSE同一REF CURSOR,改用单次OPEN + 全量FETCH,减少locator创建频次


















