Я использую библиотеку реактивных сокетов, найденную на GitHub (https://github.com/clariuslabs/reactivesockets). и мне было интересно, если кто-то испытал утечку памяти, когда клиенты подключаются и отключаются.
Я запускаю образец ReactiveServer, поставляемый с библиотекой, которая в основном состоит из:
static void Main(string[] args)
{
var port = 1055;
if (args.Length > 0)
port = int.Parse(args[0]);
var server = new ReactiveListener(port);
server.Connections.Subscribe(socket =>
{
Console.WriteLine("New socket connected {0}", socket.GetHashCode());
var protocol = new StringChannel(socket);
// Here we hook the "echo" prototocol
protocol.Receiver.Subscribe(
s => { Console.Write(s); protocol.SendAsync(s).Wait(); },
e => Console.WriteLine(e),
() => Console.WriteLine("Socket receiver completed"));
socket.Disconnected += (sender, e) => Console.WriteLine("Socket disconnected {0}", sender.GetHashCode());
socket.Disposed += (sender, e) => Console.WriteLine("Socket disposed {0}", sender.GetHashCode());
});
server.Start();
Console.WriteLine("Press Enter to exit");
Console.ReadLine();
}
Затем я создал консольное приложение с циклом, и в этом цикле создается ReactiveClient, затем он подключается к серверу, ждет 200 мс и затем отключается. Клиент не отправляет никаких данных на сервер. Это код:
static void Main(string[] args) {
var numberOfClients = 1000;
for (var i = 0; i < numberOfClients; i++) {
var controlClient = new ReactiveClient("127.0.0.1", 1055);
controlClient.ConnectAsync().Wait();
Console.WriteLine(@"Connect");
Task.Delay(200).Wait();
controlClient.Disconnect();
Console.WriteLine(@"Disconnect");
}
}
Что я вижу в профилировщике памяти Visual Studio, так это то, что использование памяти сервером растет линейно, когда я запускаю тестовое приложение. Когда тестовое приложение останавливается, использование памяти сервером не падает; он остается на любом уровне, которого достиг.
Кажется, что утечки памяти не происходит (или, по крайней мере, не так явно, с линейным ростом использования памяти), когда я запускаю образец ReactiveServer без кода, который создает экземпляр класса StringChannel и подписывается на Receiver. Код будет таким:
static void Main(string[] args) {
var port = 1055;
if (args.Length > 0)
port = int.Parse(args[0]);
var server = new ReactiveListener(port);
server.Connections.Subscribe(socket =>
{
Console.WriteLine("New socket connected {0}", socket.GetHashCode());
});
server.Start();
Console.WriteLine("Press Enter to exit");
Console.ReadLine();
}
По этой причине я подозревал, что утечка памяти может быть связана с тем, что подписка на Receiver протокола (при выполнении protocol.Receiver.Subscribe
) не удаляется должным образом при отключении клиента. Читая более подробно о Rx.NET, я прочитал, что в нормальных условиях (если наблюдаемая последовательность заканчивается) подписка автоматически удаляется, но если последовательность не завершается, она не удаляется. Я подозреваю, что последовательность не завершается, когда клиент отключается, а затем подписка не удаляется. Я попытался удалить подписку в обработчике событий Disconnected, но не увидел заметного улучшения.
Любые идеи или предложения приветствуются.
Спасибо.