UDP サーバーとして機能する単純な .net 3.5sp1 Windows アプリケーション (C#) があります。ポートでリッスンし、エンドポイントからデータを受信し、受信したデータを別のエンドポイント (つまり、ライブ ブロードキャスト データ ストリームのリレー) に再送信します。私が経験しているのは、接続が約 20 分間アップした後、悪化し始めることです。また、毎秒約 50 ~ 100K のメモリを消費していることにも気付きましたが、これは GC 後に解放されることはありません。アプリを閉じて再起動する必要があります。良くない。問題を次のコードに絞り込みました。これにより、反対側に再送信されます。
var sendBuffer = new byte[readCount];
Array.Copy(readData, sendBuffer, readCount);
SocketAsyncEventArgs args = new SocketAsyncEventArgs();
args.RemoteEndPoint = p.EP;
args.SetBuffer(sendBuffer, 0, sendBuffer.Length);
SwitchWindow.LineSocket.SendToAsync(args);
SendToAsync でメモリ リークが発生した経験がある人はいますか?
アップデート:
ソケットが初期化されるときに、状態オブジェクトをインスタンス化します (一度だけ実行します)。状態オブジェクトには、バイト配列である「buffer」と呼ばれるプロパティがあります。次のようにソケットからデータを非同期に受け取ります。
private void beginReceiveData(ref MessageState state)
{
var ipeSender = new IPEndPoint(IPAddress.Any, 0);
var epSender = (EndPoint)ipeSender;
state.workSocket = LineSocket;
state.EP = epSender;
state.workSocket.BeginReceiveFrom(state.buffer, 0, MessageState.BufferSize,
SocketFlags.None, ref epSender,
new AsyncCallback(ReceiveDataCB),
state);
}
そして、コールバック (ReceiveDataCB) で、非同期オブジェクトを取得し、バイト バッファーを別の関数に渡して処理します。これにより、上記のコードが呼び出され、反対側に再送信されます (state.buffer が readData になります)。 .
更新#2:
私の直感に従って、送信コードを次のように変更し、SocketAsyncEventArgs と SendToAsync を取り除きました。
var sendBuffer = new byte[readCount];
Array.Copy(readData, sendBuffer, readCount);
SwitchWindow.LineSocket.BeginSendTo(
sendBuffer, 0, sendBuffer.Length, SocketFlags.None,
p.EP, new AsyncCallback(echoCB), null);
そしてもちろん、EndSendTo を呼び出すだけの "echoCB" コールバックを追加しました。メモリリークがなくなりました!非常に多くの SocketAsyncEventArgs オブジェクトの作成と、これらにぶら下がっている非同期関数がパケットごとに 1 つ (1 秒あたり 33 パケットで、高速に加算される可能性があります) と関係があると思われます。SocketAsyncEventArgs の MSDN ドキュメントをもう一度見たところ、提供されたサーバーの「サンプル」コードで、SocketAsyncEventArgs オブジェクトのプールが使用されていることがわかりました。私が使っていたように機能するように設計されているとは思いません。要点は、呼び出しごとにこれらのバッファーなどをインスタンス化する必要がないため、それらを再利用してサーバーのパフォーマンスを向上させることだと思います。