リークをチェックするために、メモリプロファイラーを介してアプリケーションを実行しています。物事はある程度問題ないように見えますが、ファイナライザーキューで何もしていないように見えるこれらのOverlappedDataがたくさんあります。NetworkStream
これらは、接続のいずれかの端で基盤となるものをシャットダウンすることによってキャンセルされた、重複したIOの結果です。
ネットワークストリーム自体は破棄されます。どこにもライブインスタンスはありませんNetworkStream
。
通常、それらはと呼ばれるものに根ざしています。私が最初に行うことはコールバックでOverlappedDataCacheLine
呼び出しているので、対応するがなければへの呼び出しはありません。EndRead
BeginRead
EndRead
これは、ツールからそれを保持している人のかなり典型的な外観です
結局、それはGCされますが、それは永遠にかかります-私が約1000のストリームを開始したときにすべてを殺すのに30分ほどかかり、それらを非同期呼び出しに入れ、BeginRead
約1分後にシャットダウンします。
このプログラムは、ポート80のWebサーバーに対して問題をいくらか再現します。どのWebサーバーでも実際に実行できます。
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Threading;
class Program
{
static void Main(string[] args)
{
var clients = new List<TcpClient>();
for (int i = 0; i < 1000; ++i) {
var client = new TcpClient();
clients.Add(client);
client.BeginConnect("localhost", 80, connectResult =>
{
client.EndConnect(connectResult);
var stream = client.GetStream();
stream.BeginRead(new byte[1000], 0, 1000, result =>
{
try
{
stream.EndRead(result);
Console.WriteLine("Finished (should not happen)");
}
catch
{
// Expect to find an IO exception here
Console.WriteLine("Faulted");
}
}, stream);
}, client);
}
Thread.Sleep(10000); // Make sure everything has time to connect
foreach (var tcpClient in clients)
{
tcpClient.GetStream().Close();
tcpClient.Close();
}
clients.Clear(); // Make sure the entire list can be GC'd
Thread.Sleep(Timeout.Infinite); // Wait forever. See in profiler to see the overlapped IO take forever to go away
}
}
OverlappedData
確かに、このプログラムは実際のアプリケーションよりもはるかに小さいため、千をクリアするのに永遠にかかることはありませんが、その処理には時間がかかります。このテストアプリケーションの代わりに実際のものを実行すると、ファイナライザーがスタックしているという警告が表示されます。私のアプリケーションではあまり効果がなく、閉じられていない可能性のあるものをすべて閉じようとし、どこにも参照が保持されていないことを確認します。
Dispose()
私が電話をかけたのかClose()
、クライアントに電話をかけたのか、それがストリームであるのかは、まったく問題ではないようです。結果は同じです。
なぜこれが起こるのか、そしてこれを回避する方法についての手がかりはありますか?CLRは私にとって賢く、新しい呼び出しに備えて、これらの固定されたメモリブロックをそのまま維持しているのでしょうか。そして、なぜファイナライザーの完了が非常に遅いのですか?
更新F5キーにコップ一杯の水を入れてコーヒーを飲んで、信じられないほど愚かな負荷テストを行った後、何かがこれらのものを収集するストレス下でより完全なGCをトリガーするようです。したがって、実際には実際の問題はないように見えますが、実際にここで何が起こっているのか、なぜこのオブジェクトの収集が他のオブジェクトよりも大幅に遅いのか、そしてこれが断片化された後の段階で問題になる可能性があるのかを知ることは素晴らしいことですメモリなど。