Утечка памяти при повторном подключении/отключении с реактивными сокетами

Я использую библиотеку реактивных сокетов, найденную на 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, но не увидел заметного улучшения.

Любые идеи или предложения приветствуются.

Спасибо.


person Carlos Rodriguez    schedule 17.12.2015    source источник


Ответы (2)


Попробуйте добавить controlClient.dispose(); после отключения.

Это освободит все операционные ресурсы, используемые этим объектом.

Чтобы он читался лучше, я бы попробовал обернуть controlClient в блоке использования.

static void Main(string[] args) {
  var numberOfClients = 1000;

  for (var i = 0; i < numberOfClients; i++) {
    using{var controlClient = new ReactiveClient("127.0.0.1", 1055)) 
    {
       controlClient.ConnectAsync().Wait();
       Console.WriteLine(@"Connect");
       Task.Delay(200).Wait();
       controlClient.Disconnect();
       Console.WriteLine(@"Disconnect");
    }
  }
}
person Moose    schedule 21.12.2015
comment
Вы правы: клиент управления должен быть утилизирован. Однако утечка памяти происходит на сервере, поэтому я не вижу никаких улучшений из-за этого исправления. - person Carlos Rodriguez; 04.01.2016

Я не смог решить утечку памяти, поэтому решил заменить библиотеку. Сейчас я использую SuperSocket, и он работает очень хорошо. Проблем с памятью нет вообще.

person Carlos Rodriguez    schedule 22.01.2016
comment
Я использую суперсокет, потому что память на сервере не уменьшается после отключения клиента, есть идеи? - person user964829; 25.04.2021