Dotnet 6中Transient服务使用ActivitySource避免内存泄漏的咨询
在Transient服务中安全使用ActivitySource的解决方案
先澄清一个关键误解
你代码里的private static readonly ActivitySource不会每次实例化服务都创建新实例——静态字段属于类本身,不管创建多少个MyTransientService实例,这个ActivitySource只会被初始化一次。但如果项目中有大量这类定义了专属静态ActivitySource的Transient服务,长期运行后可能因累积的追踪资源导致内存增长。
方案1:为服务注入Singleton的ActivitySource
直接将每个服务对应的ActivitySource注册为单例,通过依赖注入使用,这是最直接的实现方式:
- 在DI容器中注册单例
ActivitySource:
// Program.cs 中配置服务 builder.Services.AddSingleton(new ActivitySource(nameof(MyTransientService))); builder.Services.AddSingleton(new ActivitySource(nameof(AnotherTransientService)));
- 在Transient服务中注入使用:
public class MyTransientService: IMyTransientService { private readonly IOtherService _otherService; private readonly ActivitySource _activitySource; public MyTransientService(IOtherService otherService, ActivitySource activitySource) { _otherService = otherService; _activitySource = activitySource; } public async Task<SomeClass> GetTransactionsFromMeniga(SomeOtherClass testObj) { using var thisActivity = _activitySource.StartActivity("New activity"); // 业务逻辑代码 } }
线程安全说明:ActivitySource是微软官方设计为线程安全的类型,多线程并发调用StartActivity不会产生线程安全问题。
方案2:用统一工厂管理所有ActivitySource
如果项目中有大量Transient服务需要使用ActivitySource,可以创建一个Singleton工厂类来集中管理,避免重复注册:
- 实现工厂类:
public interface IActivitySourceFactory { ActivitySource GetActivitySource(string sourceName); } public class ActivitySourceFactory : IActivitySourceFactory { private readonly Dictionary<string, ActivitySource> _sourceCache = new(); private readonly object _lockObj = new(); public ActivitySource GetActivitySource(string sourceName) { if (_sourceCache.TryGetValue(sourceName, out var source)) { return source; } // 双重检查锁定保证线程安全 lock (_lockObj) { if (!_sourceCache.TryGetValue(sourceName, out source)) { source = new ActivitySource(sourceName); _sourceCache.Add(sourceName, source); } } return source; } }
- 注册工厂到DI容器:
// Program.cs 中配置服务 builder.Services.AddSingleton<IActivitySourceFactory, ActivitySourceFactory>();
- 在Transient服务中使用工厂:
public class MyTransientService: IMyTransientService { private readonly IOtherService _otherService; private readonly ActivitySource _activitySource; public MyTransientService(IOtherService otherService, IActivitySourceFactory sourceFactory) { _otherService = otherService; _activitySource = sourceFactory.GetActivitySource(nameof(MyTransientService)); } public async Task<SomeClass> GetTransactionsFromMeniga(SomeOtherClass testObj) { using var thisActivity = _activitySource.StartActivity("New activity"); // 业务逻辑代码 } }
额外注意事项
ActivitySource的设计目标是长期存活的单例对象,官方推荐每个业务模块/服务只创建一个实例,而非每次使用都新建。- 若之前的代码中存在大量分散的静态
ActivitySource,换成依赖注入的单例方式后,能更清晰地管理实例生命周期,也便于后续排查内存相关问题。
内容的提问来源于stack exchange,提问作者lhn_dk
相关产品推荐
相关产品推荐

