Net6 Worker Service中Serilog记录SqlConnection异常引发内存泄漏
问题:Net6 Worker Service记录SqlConnection异常时内存飙升至8GB
我有一个Net6 Worker Service项目,使用Serilog.ILogger将错误日志写入TXT文件,近期内存占用飙升至8GB。该Worker仅负责三件事:通过Dapper从数据库获取数据、返回数据、发送邮件。
关键信息
- 使用的Serilog相关包版本:
Serilog.Extensions.Hosting5.0.0Serilog.Sinks.File5.0.0
- 内存上涨触发条件:仅当捕获SqlConnection类型异常并记录日志时,内存占用才会增加,其他类型异常无此情况。
- 当前日志记录代码:
_logger.LogError("InterfaceLogsCleanerWorker executed with exceptions" + ex.Message);
- 数据获取代码:
public async Task<List<SetupDTO>> Get() { var map = new Sys_SetupMap(); var result = new TransacResult(true, MessageTransactResult.OK); List<Sys_Setup> entityList; List<SetupDTO> list = new List<SetupDTO>(); using (var conn = new SqlConnection(this.connectionString)) { var parameters = new DynamicParameters(); parameters.Add("Result", string.Empty, DbType.String, ParameterDirection.Output); entityList = (await conn.QueryAsync<Sys_Setup>("GetSys_Setup", parameters, commandType: CommandType.StoredProcedure)).AsList(); } foreach (var entity in entityList) { list.Add(map.EntityToDTO(entity)); } return list; }
问题根源分析
- 日志记录方式错误:当前代码直接拼接
ex.Message,未将异常对象传递给Serilog。SqlConnection异常通常包含大量内部状态(如连接池信息、资源引用链),直接拼接消息会导致异常对象无法被GC正常回收——要么字符串引用了异常的部分内容,要么Serilog处理时意外持有了整个异常对象的引用,进而引发内存泄漏。 - 可能缺失日志滚动策略:若未配置日志文件按大小/时间滚动,单个日志文件过大可能导致内存中缓存的日志内容无法释放,但此情况不会仅在SqlConnection异常时触发,优先级低于前者。
修复方案
- 正确传递异常对象给Serilog:使用
LogError的重载方法传入异常对象,让Serilog正确处理异常序列化,避免持有无效引用:
_logger.LogError(ex, "InterfaceLogsCleanerWorker executed with exceptions");
- 配置日志滚动策略:确保文件Sink设置了滚动规则,防止单文件过大占用内存:
Log.Logger = new LoggerConfiguration() .WriteTo.File( path: "logs/log-.txt", rollingInterval: RollingInterval.Day, fileSizeLimitBytes: 1024 * 1024 * 100, // 单文件最大100MB retainedFileCountLimit: 30) // 保留最近30个日志文件 .CreateLogger();
- 验证资源释放逻辑:虽然代码用
using包裹了SqlConnection,但需检查Sys_Setup实体是否包含未实现IDisposable的资源,避免Dapper返回的对象持有无效引用。 - 升级Serilog包版本:当前使用的5.0.0版本存在已知内存泄漏风险,建议升级至最新稳定版。
内容的提问来源于stack exchange,提问作者JAMURILLO
相关产品推荐
相关产品推荐

