ASP.NET Core下Oracle.ManagedDataAccess.Core大查询后内存不释放求助
Oracle.ManagedDataAccess.Core 大结果集查询后内存不释放问题排查
问题核心现象
- 团队封装的统一Oracle查询类
Clases.Oracle()在常规业务场景下运行稳定,仅执行某类返回大结果集的查询时出现内存异常累积问题:单次查询最坏场景返回26万行结果,内存临时攀升至1GB本身属于可接受范围,但查询执行完成后内存始终无法主动回落 - 重复执行该类大结果集查询时,内存会随执行次数持续叠加,单线程重复执行的内存攀升上限为2GB;模拟8个并发请求场景时,内存最高可攀升至3GB
- 内存诊断工具观测显示,查询执行完成、业务结果返回很久后,Oracle驱动内部对象
OracleInternal.Common.ZoneValue仍占用大量内存 - 存在特殊的内存回落触发条件:只要执行1次返回少于100行的小结果集查询,之前累积的高内存就会快速回落至1GB以下
已开展的排查与尝试
- 已对代码中涉及的数据库连接、命令、读取器等资源型对象全部使用
using语句做隐式释放,执行完成后也在finally块中手动调用了Close()、Dispose()方法,确认无未释放的持久化资源 - 最初尝试主动调用基础版本的
GC.Collect()、GC.WaitForPendingFinalizers()做强制垃圾回收,未获得明显回收效果 - 调整强制GC的实现逻辑,使用带分代参数的双次回收策略,仅获得小幅回收改善,对应代码如下:
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced); GC.WaitForPendingFinalizers(); GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
- 关于封装类的设计判断:
Clases.Oracle()类本身仅持有连接字符串、数据库所有者名称两个字符串字段,类内使用的所有资源型对象都已做独立释放处理,因此团队认为该类本身不需要实现IDisposable接口
现有业务实现代码
封装类内的核心命令执行方法
private DataTable ExecuteReader(string package, ref OracleParameter[] parametros, string owner) { var dt = new DataTable(); using (var cn = new OracleConnection(_connection_string)) { using var cmd = cn.CreateCommand(); try { cn.Open(); cmd.CommandText = $"{owner}.{package}"; cmd.CommandType = CommandType.StoredProcedure; foreach (var par in parametros) { cmd.Parameters.Add(par); } using var rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection); dt.Load(rdr); } catch (Exception ex) { throw new Exceptions.OracleException(ex.Message); } finally { cn?.Close(); cmd?.Dispose(); cn?.Dispose(); } } return dt; }
业务侧的大结果集查询调用方法
public List<AuditoriaUsuarios> ObtieneAuditoriaUsuarios(long incluyeCargoRol = 0) { var ora = new Clases.Oracle(); var param = new OracleParameter[] { ora.AddInParameter("PIN_INCLUYECARGOROL",OracleDbType.Decimal, incluyeCargoRol), ora.AddOutCursor("CUR_OUT"), ora.AddOutParameter("PON_CODE", OracleDbType.Decimal), ora.AddOutParameter("POV_ERROR", OracleDbType.Varchar2) }; var result = ora.ExecuteReader<AuditoriaUsuarios>($"{_PCK}.p_AUDIT_USUARIOS", ref param); if (ora.HayError(param)) { throw new Exceptions.OracleException(ora.CodigoError, ora.MensajeError); } return result; }
运行环境说明
- 项目类型:x64架构ASP.NET Core WebAPI
- 技术栈:.NET Core 3.1、C#
- 开发工具:Visual Studio 2019 企业版
- 问题触发的业务场景:该大结果集数据提取操作每周仅执行数次,不属于日常高频业务,因此对强制GC带来的短暂CPU开销敏感度较低
内容的提问来源于stack exchange,提问作者Angelo Bernardi
相关产品推荐
相关产品推荐

