I'm testing a SignalR server (self-hosted in a console application) that will eventually form the basis of a data logging system. A test client is making approx 180 calls/sec to the hub, while the messages themselves are very small (just a name/value pair).
I'm using Castle Windsor for DI, with a custom IHubActivator
to resolve the Hub instance:
internal class WindsorHubActivator : IHubActivator
{
private readonly IWindsorContainer _container;
public WindsorHubActivator(IWindsorContainer container)
{
_container = container;
}
public IHub Create(HubDescriptor descriptor)
{
var hubType = descriptor.HubType;
return _container.Resolve(hubType) as IHub;
}
}
Here is the hub class:
public class TelemetryHub : Hub
{
private readonly TelemetryDataService _telemetryDataService;
public TelemetryHub(TelemetryDataService telemetryDataService)
{
_telemetryDataService = telemetryDataService;
}
public void LogTelemetryData(string name, double value)
{
_telemetryDataService.LogTelemetryData(name, value);
}
}
When the hub class is registered with Windsor as "Transient", the memory consumption climbs steadily until it hits 2Gb then falls over with an OOM exception. If I instead register the Hub as "Singleton" then the application memory consumption remains very low and consistent.
The TelemetryDataService
class is not the issue. I've commented out the hub's constructor and method code and the problem still occurs.
Out of curiosity I then took things a stage further and changed the WindsorHubActivator
class to take Windsor out of the equation:
internal class WindsorHubActivator : IHubActivator
{
...
public IHub Create(HubDescriptor descriptor)
{
return new TelemetryHub(new TelemetryDataService());
}
}
This time the memory problem went away, so I'm assuming Windsor is holding onto the created hub instances and preventing them from being garbage-collected. What's the solution? I understand it's not recommended to use a singleton Hub, and I don't want to leave the IHubActivator
in the above "hardcoded" state.