首页 > 系统相关 >C# WebSocket Fleck 内存泄漏

C# WebSocket Fleck 内存泄漏

时间:2024-09-11 16:48:02浏览次数:13  
标签:WebSocket C# System buffer Fleck error Action 客户端

最近在维护公司旧项目,内存泄漏严重,找了行业内大佬帮忙分析Dump文件(windbg我不擅长),大佬指出问题在于Fleck,这里记录一下。

整理一下问题:

1. 大佬指出 System.Threading.Tasks.ContinuationTaskFromTask 和 System.ObjectDisposedException 有71完个对象。

2. System.ObjectDisposedException 是由调用 System.Net.Sockets.NetworkStream.EndWrite(System.IAsyncResult) 方法时无法访问已释放的对象造成的。

3. System.Threading.Tasks.ContinuationTaskFromTask 也就是 Task.ContinueWith(t => { }) 过多造成的,这种写法比较传统,导致托管堆大量的 task,引发碎片化。

4. 个人观察每次释放时 都会频繁调用 Fleck.IWebSocketConnection.OnClose 事件,触发事件的 OnClose 的参数 IWebSocketConnectionInfo.Id 完全相同。

问题解决:

1. 修改了Fleck的源码,修改了Fleck.SocketWrapper 类中使用了TaskFactory.FromAsync(begin, end).ContinueWith(t => { })的内容,但感觉问题没定位到。

修改了Accept(Action<ISocket>, Action<Exception>) 方法、Receive(byte[], Action<int>, Action<Exception>, int)方法 和 Send(byte[], Action, Action<Exception>) 方法,代码如下:

public void Accept(Action<ISocket> callback, Action<Exception> error)
{
    try
    {
        Action<IAsyncResult> end = (ar) =>
        {
            try
            {
                Socket client = _socket.EndAccept(ar);
                var sw = new SocketWrapper(client);
                callback(sw);
            }
            catch (Exception e)
            {
                error(e);
            }
        };
        _socket.BeginAccept(new AsyncCallback(end), null);
    }
    catch (Exception e)
    {
        error(e);
    }
}

public void Receive(byte[] buffer, Action<int> callback, Action<Exception> error, int offset)
{
    try
    {
        Action<IAsyncResult> end = (ar) =>
        {
            try
            {
                var num = _stream.EndRead(ar);
                callback(num);
            }
            catch (Exception ex)
            {
                error(ex);
            }
        };
        _stream.BeginRead(buffer, offset, buffer.Length, new AsyncCallback(end), null);
    }
    catch (Exception e)
    {
        error(e);
    }
}
public async Task Send(byte[] buffer, Action callback, Action<Exception> error)
{
    if (_tokenSource.IsCancellationRequested)
        return;

    try
    {
        if (!_stream.CanWrite)
        {
            return;
        }
        await _stream.WriteAsync(buffer, 0, buffer.Length);
        callback();
    }
    catch (Exception e)
    {
        error(e);
    }
}

2. 研究了 WebSocket客户端代码,发现客户端多次执行了 window.ws = new window.WebSocket('ws://localhost:8181/'); 每次都赋予 window.ws 值前都没有关闭,入截图所示

修改为:创建window.WebSocket("") 和 关闭页面前都执行 window.ws.close();

3.  Fleck.IWebSocketConnection.OnClose 事件 触发时 循环所有 IWebSocketConnection 客户端集合,移除 IsAvailable==false的数据;服务器向客户端推送数据前判断 IsAvailable==true;

 

上面的修改后 两周过去了,但问题还是没有解决,中间还是各种尝试。这里做下总结

问题是:TCP协议需要客户端确认接收,WebSocket频繁发送消息到客户端时,可能某些原因客户端卡顿了不能及时确认回复,导致Task一直停留在EndWrite()的回调中直到连接关闭。

 期间进行了各种尝试:

1. 打印 当前客户端连接数量,确实监控到一下额外的客户端。

2. 修改 Fleck.SocketWrapper.cs 类,构造方法中增加 socket.ReceiveTimeout = 1000 和 socket.SendTimeout = 1000 的设置。也就是1秒超时。

3. 当内存增大时,手动关闭客户端连接。过段时间内存也确实降了下来。

4. 也看了 System.Net.Sockets.Socket 和 System.Net.Sockets.NetworkStream 的源码,但没有太大的入手的。

最后通过修改客户端代码解决的,修改了一些数组只Push 不 Shift 的问题。要怪只能怪写客户端的人太部分责任了。

 

标签:WebSocket,C#,System,buffer,Fleck,error,Action,客户端
From: https://www.cnblogs.com/KarlAlbright/p/18389142

相关文章

  • CheckSum算法--又名累加和校验算法
    校验和(Checksum)是网络协议使用的数据错误检测方法,并且被认为比LRC(纵向冗余校验,LongitudinalRedundancyCheck,LRC),VRC和CRC(循环冗余校验(CyclicRedundancyCodes,CRC))更可靠。此方法在发送方使用校验和生成器,在接收方使用校验和校验器。累加和校验算法的实现发送方:对要数据累加,得......
  • PDshell16逆向PostgreSQL 工程显示字段comment备注
    现状:当刚逆向成功的表结构是没有原来表结构中的,comment备注如下 然后pd逆向工程的sql已经返回了这个备注的含义 解决方案:1、设置显示注释列tools——DisplayPreferences…如下    勾选-按照下面得方式勾选这三个 复制这里的VBS脚本,打开菜单Tools>Execute......
  • C语言中 '=='的优先级高于 '&' '|' '&&' '||'
    之前一直以为 '=='的优先级低于  '&''|',但是这是错误的, '=='的优先级高于'&''|''&&''||',同时使用时,记得加括号修改优先级。 第一优先级:[]       ()      .      ->   方括号,圆括号,对象,......
  • solidworks卸载工具,专用卸载修复工具,一键卸载solidworks ae ai ansys arcgis catia c
    XXClean是一款专业的系统清理工具,旨在帮助用户彻底卸载和清理各种软件残留。它支持广泛的软件列表,aeaiansysArcGlSCatiaCDRCreoDaVinciMastercamMatlabMultisimofficeOriginProepsRhinoSketchupSPSSsolidworksTIAPortalUGNX软件等。以下是XXClean的简介......
  • 在Navicat中对postgre数据库批量修改表的Owner
     navicat中可以在General中看到Owner的信息,需要修改某个表的Owner时,可以在设计表的Options选项中修改  但是表比较多的时候不太方便,可以使用sql命令来修改:select'ALTERTABLE'||table_name||'OWNERTOtargetOwner;'frominformation_schema.tableswhereta......
  • 22级五年制C语言入门教程-(5)格式化输入输出
    1.输入和输出在程序的使用中,我们经常可以看的这么一个场景:用户需要输入数据,经过程序运算,得到结果后输出。在C语言中,输入数据和输出数据都是由库函数完成的,通过语句来输入/输出。2.格式化输出—printf()函数C语言程序运算的结果在内存中,我们需要将其输出到指定设备中,我们才可以......
  • 22级五年制C语言入门教程-(6)运算符
    1.运算符概述运算符是一种编译器执行特定的数学或逻辑操作的符号。C语言提供了以下类型的运算符:算术运算符关系运算符逻辑运算符位运算符赋值运算符条件运算符其他运算符2.算术运算符算术运算符分为单目运算符和双目运算符,单目运算符表示只需要一个操作数,双目运算符需......
  • PowerDesigner 逆向工程 Could not Initialize JavaVM!
    原项目的大量的表,使用PowerDesigner进行逆向工程。提示CouldnotInitializeJavaVM! 网上找到原因,PowerDesigner不可以使用64位JDK环境! 有一种不修改环境变量的方法在PowerDesigner目录下,建立一个启动批处理,如:startup.bat,在其中配置JAVA_HOME、CLASSPATH,如下例所示: ......
  • 基于深度学习的骨龄检测识别系统(PyTorch+Pyside6+YOLOv5模型)
    骨龄是骨骼年龄的简称,需要借助于骨骼在X光摄像中的特定图像来确定。通常要拍摄左手手腕部位的X光片,医生通过X光片观察来确定骨龄。在2006年,《中华-05》骨龄标准被编入《中华人民共和国行业标准》,成为中国目前唯一的行业骨龄标准。而在《中华-05》中作者一般推荐使用RUS-CHN计......
  • 启程,新手学习c语言的第一天
     今天是我开始学习c语言的第一天,通过网上查询资料得知写博客对程序员的成长有很大帮助,于是开始在学习的同时开始写一写博客。 我明白自己是一个什么都不知道的新手,一开始也写不出什么有实质性内容的东西。所以目前的播客主要是记录自己的学习经历,通过这一方式来对学习过的......