streamWriterBufferedDataLost MDA

Note

この記事は .NET Framework に固有のものです。 .NET 6 以降のバージョンを含む、.NET の新しい実装には適用されません。

streamWriterBufferedDataLost マネージド デバッグ アシスタント (MDA) は StreamWriter が書き込まれたときに起動しますが、その後、StreamWriter のインスタンスが破棄される前に Flush または Close メソッドが呼び出されません。 この MDA が有効になると、バッファーに入れられたデータが StreamWriter 内に残っているか、ランタイムにより判断されます。 バッファーに入れられたデータが残っている場合、MDA が起動します。 Collect メソッドと WaitForPendingFinalizers メソッドを呼び出すことで、ファイナライザーを強制的に実行できます。 それ以外の場合、ファイナライザーは任意のタイミングで実行されます。プロセス終了時に実行されることは、ほぼありません。 この MDA が有効になっている状態でファイナライザーを明示的に実行すると、この種類の問題をより確実に再現できます。

現象

StreamWriter では、最後の 1 – 4 KB のデータがファイルに書き込まれません。

原因

StreamWriter はデータを内部でバッファーに入れます。このとき、Close または Flush メソッドを呼び出し、バッファーに入れたデータを基礎となるデータ ストアに書き込む必要があります。 Close または Flush が正しく呼び出されない場合、StreamWriter インスタンスのバッファーに入れられたデータは予想どおりに書き込まれないことがあります。

次は、この MDA がキャッチする、書き込みが十分ではないコードの例です。

// Poorly written code.
void Write()
{
    StreamWriter sw = new StreamWriter("file.txt");
    sw.WriteLine("Data");
    // Problem: forgot to close the StreamWriter.
}

開始したガベージ コレクションがファイナライザーの完了まで保留となる場合、先行のコードがこの MDA をより確実に起動します。 この種類の問題を追跡するために、デバッグ ビルドで、先行メソッドの終わりに次のコードを追加できます。 これで MDA が起動する確率が高くなりますが、もちろん、問題の根本原因が解消されるわけではありません。

GC.Collect();
GC.WaitForPendingFinalizers();

解決方法

アプリケーションを閉じる前に、あるいは、StreamWriter のインスタンスが含まれるコード ブロックを終了する前に、StreamWriterClose または Flush を呼び出します。 これを最も効率的に行う方法は、C# using ブロック (Visual Basic の場合、Using) でインスタンスを作成することです。ライターの Dispose メソッドが呼び出され、インスタンスが正しく終了します。

using(StreamWriter sw = new StreamWriter("file.txt"))
{
    sw.WriteLine("Data");
}

次のコードは同じ解決策ですが、using の代わりに try/finally が使用されています。

StreamWriter sw;
try
{
    sw = new StreamWriter("file.txt"));
    sw.WriteLine("Data");
}
finally
{
    if (sw != null)
        sw.Close();
}

いずれの解決策も利用できない場合 (StreamWriter が静的変数に保存されており、その有効期間の終わりにコードを実行することが簡単でない場合など)、最後に使用した後で StreamWriterFlush を呼び出すか、最初に使用する前に AutoFlush プロパティを true に設定すると、この問題を解決できるはずです。

private static StreamWriter log;
// static class constructor.
static WriteToFile()
{
    StreamWriter sw = new StreamWriter("log.txt");
    sw.AutoFlush = true;

    // Publish the StreamWriter for other threads.
    log = sw;
}

ランタイムへの影響

この MDA は、ランタイムに影響しません。

出力

この違反が発生したことを示すメッセージ

構成

<mdaConfig>
  <assistants>
    <streamWriterBufferedDataLost />
  </assistants>
</mdaConfig>

関連項目