2

GitHub ( https://github.com/clariuslabs/reactivesockets )で見つけた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 のメモリ プロファイラーを見ると、テスト アプリケーションを実行すると、サーバーのメモリ使用量が直線的に増加することがわかります。テスト アプリケーションが停止しても、サーバーのメモリ使用量は低下しません。到達したレベルにとどまります。

StringChannel クラスをインスタンス化し、Receiver をサブスクライブするコードを使用せずに 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());
  });

  server.Start();

  Console.WriteLine("Press Enter to exit");
  Console.ReadLine();
}

そのため、メモリ リークはprotocol.Receiver.Subscribe、クライアントが切断されたときにプロトコルのレシーバーへのサブスクリプション (実行時) が適切に破棄されないことに関連している可能性があるのではないかと疑っていました。Rx.NET について詳しく読むと、通常の状況 (監視可能なシーケンスが終了した場合) では、サブスクリプションは自動的に破棄されますが、シーケンスが完了しない場合は破棄されないことを読みました。クライアントが切断されたときにシーケンスが完了せず、サブスクリプションが破棄されていないと思われます。Disconnected イベント ハンドラーでサブスクリプションを破棄しようとしましたが、目立った改善は見られませんでした。

アイデアや提案は大歓迎です。

ありがとう。

4

2 に答える 2

2

メモリリークを解決できなかったので、ライブラリを置き換えることにしました。私は現在SuperSocketを使用していますが、非常にうまく機能しています。メモリの問題はまったくありません。

于 2016-01-22T09:50:04.150 に答える
2

controlClient.dispose();切断後に追加してみてください。

これにより、そのオブジェクトによって使用されているすべての操作リソースが解放されます。

読みやすくするために、controlClient を using ブロックでラップしてみます。

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");
    }
  }
}
于 2015-12-21T12:23:44.903 に答える