高速で継続的な読み取り/書き込みループを使用してネットワーク デバイスと通信する C#、UWP 10 ソリューションを開発しています。API によって提供される StreamSocket はうまく機能しているように見えましたが、メモリ リークが発生していることに気付きましたTask<uint32>
。1 分間に数百単位のメモリ リークがヒープに蓄積されています。
内で単純な古いwhile (true)
ループを使用するか、TPL Dataflow でasync Task
自己投稿を使用するかに関係なく (この回答ActionBlock<T>
に従って)、結果は同じです。
ソケットからの読み取りをなくして書き込みに集中すれば、問題をさらに切り分けることができます。DataWriter.StoreAsync
アプローチを使用するか、より直接的なを使用するかに関係なくStreamSocket.OutputStream.WriteAsync(IBuffer buffer)
、問題は残ります。さらに、.AsTask()
これらに を追加しても違いはありません。
ガベージ コレクタが実行されても、これらTask<uint32>
の はヒープから削除されません。これらのタスクはすべて完了しており ( RanToCompletion
)、エラーや、「再利用の準備が整っていない」ことを示すその他のプロパティ値はありません。
このページに私の問題のヒントがあるようです(バイト配列が管理された世界から管理されていない世界に移動すると、メモリの解放が妨げられます)、規定された解決策は非常に厳しいようです: これを回避する唯一の方法は、すべての通信ロジックをC++/CX。これが真実ではないことを願っています。確かに、他の C# 開発者は、メモリ リークのない継続的な高速ネットワーク通信を成功裏に実現しています。確かに Microsoft は、C++/CX でメモリ リークなしでのみ機能する API をリリースしないでしょう。
編集
リクエストに応じて、いくつかのサンプル コード。私自身のコードにはレイヤーが多すぎますが、この Microsoft サンプルでは、はるかに単純な例を見ることができます。問題を強調するために、ループで 1000 回送信するように簡単な変更を加えました。これは関連するコードです:
public sealed partial class Scenario3 : Page
{
// some code omitted
private async void SendHello_Click(object sender, RoutedEventArgs e)
{
// some code omitted
StreamSocket socket = //get global object; socket is already connected
DataWriter writer = new DataWriter(socket.OutputStream);
for (int i = 0; i < 1000; i++)
{
string stringToSend = "Hello";
writer.WriteUInt32(writer.MeasureString(stringToSend));
writer.WriteString(stringToSend);
await writer.StoreAsync();
}
}
}
Task<UInt32>
アプリを起動してソケットを接続すると、ヒープ上に のインスタンスしかありません。「SendHello」ボタンをクリックすると、86 個のインスタンスがあります。2回目押したら129回。
編集#2 アプリ(タイトループの送受信を使用)を3時間実行した後、間違いなく問題があることがわかります.50万個のタスクインスタンスがGCされず、アプリのプロセスメモリが初期から上昇しました46MB~105MB。明らかに、このアプリは無期限に実行できません。 ただし...これはデバッグモードでの実行にのみ適用されます。アプリをリリースモードでコンパイルし、展開して実行すると、メモリの問題は発生しません。一晩中実行したままにできますが、メモリが適切に管理されていることは明らかです。ケースを閉じました。