I have a web application that sends messages from the server to the front end (Javascript) client using SignalR. However, there is also a back end (.NET) client that creates a proxy to the hub. The back end client processes messages and sends them to the hub, and the hub then sends these messages to the front end client.
Here is a snippet of the back end client that creates the hub connection and proxy to send messages to the hub:
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);
}
There is obviously more to the code, but that covers the essential part.
The key part is, every time a message is created, this code is called. That means there is a HubConnection
object created for every message that needs to be sent to the hub, and then to the front end client. After making a memory dump, I realized a lot of objects remain on the heap and is causing a memory leak. I figured it's because I'm not disposing the hub connection, since one of the main culprits is Microsoft.AspNet.SignalR.Transports.LongPollingTransport
, with over a thousand objects on the heap after playing around with the website for about an hour (doing things that would create these SignalR messages).
So I thought disposing HubConnection
would fix things:
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;
}
But after running the process and attaching WinDbg to it, when I do -!dumpheap -stat -type Microsoft.AspNet.SignalR.Transports
, again I see Microsoft.AspNet.SignalR.Transports.LongPollingTransport
up there with similar high figures for objects on the heap + memory. Shouldn't the using statement cause HubConnection
to be disposed and therefore removed from the heap? What should I be doing to fix this memory leak?
It turns out that disposing the hub connection does work. I was conflating two concepts: disposing unmanaged resources and deleting objects from the heap.
I thought that when the using statement for the HubConnection
object finishes (i.e., when dispose is called on HubConnection
), WinDbg would no longer show that object in the memory dump. But since the memory dump is based on what's on the heap, and since disposing an object doesn't delete the object from the heap (just allows it to be released and deleted by the garbage collector), it was still showing in WinDbg.
I played around with the application more until the garbage collector did its work, and found that the objects were deleted later.
I should also note that my original question emphasized the type Microsoft.AspNet.SignalR.Transports.LongPollingTransport
, and that was because I was not disposing the LongPollingTransport
object either (when I do hubConnection.Start(new LongPollingTransport())
. So my code now looks like the following:
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;
}
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加