C# --- 单例类错误初始化 + 没有释放资源导致线程泄漏
C# --- 单例类错误初始化 + 没有释放资源导致线程泄漏
- Background
- 原因分析
- 问题一: 错误初始化(使用了箭头函数)
- 问题一: 没有Dispose资源
Background
- 背景: service A的其中一个Api会向mq发送消息
- 问题:线上发现这个服务经常有几百个线程在同时运行,怀疑是发生了线程泄漏
- 什么是线程泄漏:代码产生了大量的不应该出现的线程,导致占用过多资源,严重影响系统性能
原因分析
经过排查发现了一下问题代码
public class Dispatch
{public static Dispatch Instance => new Dispatch();private readonly Sender senderpublic Dispatch() { sender = new Sender();}
}public class Sender : IDisposable
{private readonly Task _recoveryTask;public Sender() { recoveryTask = Task.Factory.StartNew(new Action(this.ReceoveryTaskEntry), TaskCreationOptions.LongRunning)}private void RecoveryTaskEntry() {while (!this.Disposed){//impl}}public void Dispose() {_recoveryTask.Dispose()GC.SuppressFinalize(this); // 阻止终结器调用}
}
问题一: 错误初始化(使用了箭头函数)
public static Dispatch Instance => new Dispatch();//等价于
public static Dispatch Instance()
{return new Dispatch();
}
以上代码在 Dispatch.Insatnce
被调用时每次都会新建一个Dispatch实例,而Dispatch的构造方法里会创建并运行一个新的线程,也就是说每个requets都会创建一个新的线程
正确的初始化:保证单例类只有一个实例
public static Dispatch Instance { get; } = new Dispatch();
问题一: 没有Dispose资源
在Dispatch中没有dispose sender, 导致线程没有被释放
public class Dispatch
{public static Dispatch Instance => new Dispatch();private readonly Sender senderpublic Dispatch() { sender = new Sender();}
}
正确实现:在Dispose中释放资源
public class Dispatch
{public static Dispatch Instance => new Dispatch();private readonly Sender senderpublic Dispatch() { sender = new Sender();}public void Dispose() {sender.Dispose()//....}
}