C# --- 单例类错误初始化 + 没有释放资源导致线程泄漏
Background
- 背景: service A的其中一个Api会向mq发送消息
- 问题:线上发现这个服务经常有几百个线程在同时运行,怀疑是发生了线程泄漏
- 什么是线程泄漏:代码产生了大量的不应该出现的线程,导致占用过多资源,严重影响系统性能
原因分析
经过排查发现了一下问题代码
public class Dispatch
{
public static Dispatch Instance => new Dispatch();
private readonly Sender sender
public 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 sender
public Dispatch()
{
sender = new Sender();
}
}
正确实现:在Dispose中释放资源
public class Dispatch
{
public static Dispatch Instance => new Dispatch();
private readonly Sender sender
public Dispatch()
{
sender = new Sender();
}
public void Dispose() {
sender.Dispose()
//....
}
}