查找WebSocket服务器内存泄漏
大家好,我目前正在测试一个用Asp.Net Core 2.0编写的websocket服务器,我相信我有内存泄漏。我无法找到它,尽管我已经尝试处理了所有可能引起关注的问题。查找WebSocket服务器内存泄漏,websocket,.net-core,webserver,Websocket,.net Core,Webserver,大家好,我目前正在测试一个用Asp.Net Core 2.0编写的websocket服务器,我相信我有内存泄漏。我无法找到它,尽管我已经尝试处理了所有可能引起关注的问题。测试是连续进行的,ram的值在达到稳定状态时计算。(这从5秒到20秒不等)。 使用普通任务管理器监视器测量占用的Ram。测试工具:Thor: 命令:thor--amount[amount]ws://[HostIP(localhost)]:[portnumber] 结果: Connections | RAM Consumed at
测试是连续进行的,ram的值在达到稳定状态时计算。(这从5秒到20秒不等)。
使用普通任务管理器监视器测量占用的Ram。
测试工具:
Thor
:命令:
thor--amount[amount]ws://[HostIP(localhost)]:[portnumber]
结果:
Connections | RAM Consumed at the end of test (GB):
0 4.54
50 4.55
100 4.55
150 4.61
200 4.68
300 4.76
400 4.59
400 4.59
500 4.62
500 4.65
550 4.65
WebSocket服务器:
SocketMiddleware-由appbuilder使用:
public class SocketMiddleware
{
public byte[] ToSegment(string message) => System.Text.Encoding.UTF8.GetBytes(message);
ClientTracker clientTracker; //the socket clients tracker this is the object we're speaking of
RequestDelegate next;
public SocketMiddleware(ClientTracker tracker,RequestDelegate del)
{
this.clientTracker=tracker;
this.next=del;
}
public async Task Invoke(HttpContext context)
{
if(!context.WebSockets.IsWebSocketRequest)
{
await this.next.Invoke(context);
return;
}
await this.clientTracker.AddClient(context.WebSockets);
}
}
SocketTracker-这是处理所有打开的插座的嫌疑人
public class ClientTracker
{
ConcurrentDictionary<string, Client> clientMap = new ConcurrentDictionary<string, Client>();
public string CreateConnectionID() => Guid.NewGuid().ToString();
public string GetIDOfSocket(WebSocket socket) => this.clientMap.First(x => x.Value.webSocket.Equals(socket)).Key;
public Client GetClientByID(string id)
{
this.clientMap.TryGetValue(id, out Client client);
return client;
}
public async Task AddClient(WebSocketManager manager)
{
using (WebSocket socket = await manager.AcceptWebSocketAsync())
{
Client newClient = Client.CreateClient(socket, CreateConnectionID());
if(clientMap.TryAdd(newClient.clientID, newClient))
{
await ReceiveMessage(newClient);
}
}
}
public async Task ReceiveMessage(Client client)
{
while (client.webSocket.State == WebSocketState.Open)
{
WebSocketReceiveResult result = await client.ReceiveResult();
//dosomething with result...
if (result.MessageType == WebSocketMessageType.Close)
{
await client.webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Client closed", CancellationToken.None);
break;
}
//send custom message
await client.SendMessage("lala");
}
}
}
公共类ClientTracker
{
ConcurrentDictionary clientMap=新建ConcurrentDictionary();
公共字符串CreateConnectionID()=>Guid.NewGuid().ToString();
公共字符串GetIDOfSocket(WebSocket套接字)=>this.clientMap.First(x=>x.Value.WebSocket.Equals(socket)).Key;
公共客户端GetClientByID(字符串id)
{
this.clientMap.TryGetValue(id,out-Client);
返回客户;
}
公共异步任务AddClient(WebSocketManager)
{
使用(WebSocket套接字=等待管理器.AcceptWebSocketAsync())
{
Client newClient=Client.CreateClient(socket,CreateConnectionID());
if(clientMap.TryAdd(newClient.clientID,newClient))
{
等待接收消息(新客户端);
}
}
}
公共异步任务接收消息(客户端)
{
while(client.webSocket.State==WebSocketState.Open)
{
WebSocketReceiveResult结果=等待客户端。ReceiveResult();
//结果是。。。
if(result.MessageType==WebSocketMessageType.Close)
{
wait client.webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure,“客户端已关闭”,CancellationToken.None);
打破
}
//发送自定义消息
等待客户发送消息(“lala”);
}
}
}
客户端-SocketTrapper,对套接字执行所有必需的操作,并存储跟踪程序使用的临时数据
public class Client
{
//Fields
public readonly WebSocket webSocket;
public readonly string clientID;
public StringBuilder tempData;
//Auxiliary
private const int BufferSize = 1024 * 4;
public static Client CreateClient(WebSocket socket, string id)
{
Client client = new Client(socket, id);
return client;
}
public Client(WebSocket socket, string id)
{
this.webSocket = socket;
this.clientID = id;
tempData = new StringBuilder();
}
public async Task<WebSocketReceiveResult> ReceiveResult()
{
tempData.Clear();
ArraySegment<byte> segment = new ArraySegment<byte>(new byte[BufferSize]);
WebSocketReceiveResult result = await this.webSocket.ReceiveAsync(segment, CancellationToken.None);
tempData.Append(BitConverter.ToString(segment.Array));
return result;
}
public async Task SendMessage(string message)
{
byte[] bytes = Encoding.UTF8.GetBytes(message);
await this.webSocket.SendAsync(new ArraySegment<byte>(bytes), WebSocketMessageType.Text, true, CancellationToken.None);
}
}
公共类客户端
{
//田地
公共只读WebSocket WebSocket;
公共只读字符串clientID;
公共数据;
//辅助的
private const int BufferSize=1024*4;
公共静态客户端CreateClient(WebSocket套接字,字符串id)
{
客户端=新客户端(套接字,id);
返回客户;
}
公共客户端(WebSocket套接字,字符串id)
{
this.webSocket=套接字;
this.clientID=id;
tempData=新的StringBuilder();
}
公共异步任务ReceiveResult()
{
tempData.Clear();
ArraySegment段=新的ArraySegment(新字节[BufferSize]);
WebSocketReceiveResult结果=等待this.webSocket.ReceiveAsync(段,CancellationToken.None);
Append(BitConverter.ToString(segment.Array));
返回结果;
}
公共异步任务SendMessage(字符串消息)
{
byte[]bytes=Encoding.UTF8.GetBytes(消息);
等待这个.webSocket.SendAsync(新的ArraySegment(字节),WebSocketMessageType.Text,true,CancellationToken.None);
}
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddSingleton<ClientTracker>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseWebSockets();
app.UseMiddleware<SocketMiddleware>();
}
public void配置服务(IServiceCollection服务)
{
services.AddMvc();
services.AddSingleton();
}
公共无效配置(IApplicationBuilder应用程序,IHostingEnvironment环境)
{
if(env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseWebSockets();
app.UseMiddleware();
}
附言:
请求之间未关闭服务器。可能是并发字典吗?除此之外,客户端的引用已清理,客户端已释放,套接字已关闭。无法释放字符串生成器,追踪器/中间件的寿命与应用程序的寿命一样长。今天,我面临着同样的问题,显然没有解决方案。我有4万个独家产品,内存为1GB。当我关闭更新时,内存保持高位