我有一个Web应用程序,使用SignalR将消息从服务器发送到前端(Javascript)客户端。但是,还有一个后端(.NET)客户端,它可以为集线器创建代理。后端客户端处理消息并将其发送到集线器,然后集线器将这些消息发送到前端客户端。
以下是后端客户端的一个片段,它创建了集线器连接和代理,以便向集线器发送消息:
HubConnection hubConnection = new HubConnection(serverUrl);
IHubProxy hubProxy = hubConnection.CreateHubProxy(hubName);
Task t = Task.Run(() => hubConnection.Start(new LongPollingTransport()));
t.WaitAndUnwrap();
if (hubProxy != null && hubConnection.State == ConnectionState.Connected)
{
await hubProxy.Invoke("MessageClients", messageArgs);
}
代码显然有更多,但这涵盖了必不可少的部分。
关键部分是,每次创建消息时,都会调用此代码。这意味着为每个需要发送到集线器,然后发送到前端客户端的消息创建了一个HubConnection
对象。
进行内存转储后,我意识到堆上有很多对象,并导致内存泄漏。我认为这是因为我没有处理集线器连接,因为其中一个主要罪魁祸首是Microsoft.AspNet.SignalR.Transports.LongPollingTransport
,在网站上玩了大约一个小时之后,堆上有超过一千个对象(做一些会创建的东西)这些SignalR消息)。
所以我认为处理HubConnection
会解决问题:
using (HubConnection hubConnection = this.CreateHubConnection())
{
if (hubConnection != null)
{
IHubProxy hubProxy = this.StartConnection(hubConnection);
if (hubProxy != null && hubConnection.State == ConnectionState.Connected)
{
await hubProxy.Invoke("MessageClients", messageArgs);
}
}
}
private HubConnection CreateHubConnection()
{
// do some basic auth set up
HubConnection hubConnection = new HubConnection(this.serverUrl);
hubConnection.Headers.Add('authToken', basicAuth);
return hubConnection;
}
private IHubProxy StartConnection(HubConnection hubConnection)
{
IHubProxy hubProxy = hubConnection.CreateHubProxy(this.hubName);
Task t = Task.Run(() => hubConnection.Start(new LongPollingTransport())
t.WaitAndUnwrap();
return hubProxy;
}
但是在运行该过程并将WinDbg附加到它之后,当我执行-!dumpheap -stat -type Microsoft.AspNet.SignalR.Transports
时,我再次看到Microsoft.AspNet.SignalR.Transports.LongPollingTransport
那里的堆+内存上的对象具有相似的高数字。 using语句是否应该导致HubConnection
被处置并因此从堆中删除?我该怎么做才能修复这个内存泄漏?
答案 0 :(得分:0)
事实证明,部署集线器连接确实有效。我混淆了两个概念:处理非托管资源和从堆中删除对象。
我认为当HubConnection
对象的using语句结束时(即,在HubConnection
上调用dispose时),WinDbg将不再在内存转储中显示该对象。但是由于内存转储是基于堆上的内容,并且由于处理对象不会从堆中删除对象(只允许它被垃圾收集器释放和删除),它仍然在WinDbg中显示。 / p>
我更多地使用应用程序,直到垃圾收集器完成其工作,并发现稍后删除了对象。
我还应该注意,我的原始问题强调类型Microsoft.AspNet.SignalR.Transports.LongPollingTransport
,这是因为我没有处置LongPollingTransport
对象(当我hubConnection.Start(new LongPollingTransport())
时。所以我的代码现在如下所示:
using (HubConnection hubConnection = this.CreateHubConnection())
{
if (hubConnection != null)
{
using (LongPollingTransport lpTransport = newLongPollingTransport())
{
IHubProxy hubProxy = this.StartConnection(hubConnection, lpTransport);
if (hubProxy != null && hubConnection.State == ConnectionState.Connected)
{
await hubProxy.Invoke("MessageClients", messageArgs);
}
}
}
}
private HubConnection CreateHubConnection()
{
// do some basic auth set up
HubConnection hubConnection = new HubConnection(this.serverUrl);
hubConnection.Headers.Add('authToken', basicAuth);
return hubConnection;
}
private IHubProxy StartConnection(HubConnection hubConnection, HttpBasedTransport transport)
{
IHubProxy hubProxy = hubConnection.CreateHubProxy(this.hubName);
Task t = Task.Run(() => hubConnection.Start(transport));
t.WaitAndUnwrap();
return hubProxy;
}