C# --- 单例类错误初始化 + 没有释放资源导致线程泄漏

发布于:2025-07-17 ⋅ 阅读:(23) ⋅ 点赞:(0)

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()
        //....
    }
}

网站公告

今日签到

点亮在社区的每一天
去签到