You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core中WebSocket请求使用时被垃圾回收的原因

ASP.NET Core WebSocket场景下资源被GC回收但连接仍保持的问题

代码示例

[Route("ws")]
public async Task WebSocket()
{
    using (var data = new Data()) 
    {
        if (HttpContext.WebSockets.IsWebSocketRequest) 
        {
            using var webSocket = await HttpContext.WebSockets.AcceptWebSocketAsync();
            var tcs = new TaskCompletionSource();
            // 此处为WebSocket业务代码,已移除以简化复现
            await tcs.Task;
        }
        else 
        {
            HttpContext.Response.StatusCode = StatusCodes.Status400BadRequest;
        }
    }
}

class Data : IDisposable
{
    public void Dispose()
    {
        throw new NotImplementedException();
    }

    ~Data()
    {
        Console.WriteLine("Data disposed");
    }
}

问题描述

data及注释位置的其他资源已被垃圾回收,但WebSocket仍处于连接状态,TaskCompletionSource未完成、Action任务也未完成。该代码与微软ASP.NET Core文档中的WebSocket示例非常接近,为何会出现这种情况?

原因分析

  1. using块的执行时机:using (var data = new Data())的Dispose()方法会在整个代码块执行完毕后才调用,但代码执行到await tcs.Task时会挂起,整个using块并未结束,所以Dispose()并未触发。你看到的"Data disposed"是对象终结器(~Data())的输出,说明data对象被GC回收了。
  2. GC的回收逻辑:data变量在进入WebSocket分支后,没有再被任何代码引用,即使它还处于using块的作用域内,GC依然可以回收这个不再被使用的对象。GC只关心对象是否有活跃引用,不关心它是否在using块中。
  3. 请求Task未被回收:ASP.NET Core并没有回收请求Task,因为await tcs.Task让整个Action任务处于挂起等待状态,所以WebSocket连接能保持。微软官方示例中通常会在WebSocket的消息处理循环中持续持有资源引用,或者资源在会话全程被使用,所以不会被GC回收,而你的代码中data提前失去了引用,才会被GC回收。

解决建议

  • 如果Data对象需要在WebSocket会话全程存活,要在WebSocket的业务处理逻辑中保持对它的引用,比如把它传入处理方法、或者作为局部变量保留引用,避免GC回收。
  • 正确实现IDisposable接口,确保Dispose()能正常执行(当前代码中Dispose()抛出异常,会导致using块结束时出错),如果需要在会话结束时释放资源,应该在tcs.SetResult()之后让using块正常结束,触发Dispose()。

内容的提问来源于stack exchange,提问作者maloo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 10:22:42