Skip to main content
 首页 » 编程设计

c#之SignalR 中的内存使用情况会重新启动 ASP.NET Web 应用程序

2024年01月26日26zdz8207

我正在试用一个用 ASP.NET MVC (C#) 编写的在线游戏,使用 SignalR 实现游戏的实时方面,并作为 Azure Web 应用托管。这是一个相当简单的桌面游戏,但我遇到了一个问题,即在高峰负载(晚上和周末)下,应用程序使用过多内存,工作进程自动重启。

这是我的 SignalR 连接类的粗略代码大纲(包括日志记录、空检查等)已删除:

namespace MyApp.Connections 
{ 
    public class GameConnection : PersistentConnection 
    { 
        protected override Task OnDisconnected(IRequest request, string connectionId, bool stopCalled) 
        { 
            Game game = GameService.GetGameByConnectionId(connectionId); 
            List<Task> connectionTasks = new List<Task>(); 
            Player player = game.GetPlayer(connectionId); 
 
            game.RemovePlayer(player); 
 
            foreach (Player playerToUpdate in game.Players) 
            { 
                GameActionResponse response = new GameActionResponse(game); 
                response.Message = string.Format("Player '{0}' has left the game.", player.Name); 
                connectionTasks.Add(Connection.Send(playerToUpdate.ConnectionId, response)); 
            }           
 
            return Task.WhenAll(connectionTasks); 
        } 
 
        protected override Task OnReceived(IRequest request, string connectionId, string data) 
        { 
            Game game = GameService.GetGameByConnectionId(connectionId); 
            List<Task> connectionTasks = new List<Task>(); 
            Player actingPlayer = game.GetPlayer(connectionId); 
 
            GameAction action = JsonConvert.DeserializeObject<GameAction>(data); 
            GameActionResponse response = new GameActionResponse(game); 
            game.ProcessAction(action, actingPlayer, response); 
 
            foreach (Player playerToUpdate in game.Players) 
            { 
                response.Message = response.Description; 
                response.From = actingPlayer.Name; 
                connectionTasks.Add(Connection.Send(playerToUpdate.ConnectionId, response)); 
            } 
 
            return Task.WhenAll(connectionTasks); 
        } 
    } 
} 

基本上,我只是响应消息,使用它们来更改游戏状态(关闭连接 ID 以确定正确的玩家),然后用新的游戏状态(我的 GameActionResponse 类)回复玩家.我不使用 Connection.Broadcast,因为我需要为每个玩家定制响应(尽管上面没有显示该代码)。

当它在相当重的负载下运行时,我让 Azure 给我一个 w3wp.exe 的内存转储,通过 Visual Studio 中的探查器运行它,结果如下,按包含大小排序:

这表明 SignalR 或(更有可能)我对它的使用存在问题。我的问题是:我在处理 SignalR 连接和消息的方式上是否做错了什么?

可能是消息的大小和数量?一个典型的客户端 -> 服务器消息小于 1K(仅包含玩家采取的操作),但服务器 -> 客户端响应消息可以是 5-10K 到 30K 的“完全刷新”消息。

请您参考如下方法:

SignalR 有一个环形缓冲区,用于保存每个信号的消息。默认情况下,缓冲区大小为 1000 条消息,因此如果您有许多连接的客户端,则会存储大量消息。 (此缓冲区的用途之一是能够发送客户端可能因重新连接而错过的消息)您可以尝试通过更改 DefaultMessageBufferSize property 来减少缓冲区.此缓冲区的最小大小为 32 和 it is enforced by SignalR (即设置值低于 32 将为您提供 32,低于 0 将为您提供异常(exception))。您需要尝试使用此值 - 如果您有很多消息而该值太小,您可能会开始丢失消息。