Compartilhar via


MDA streamWriterBufferedDataLost

Observação

Este artigo é específico para aplicativos .NET Framework. Ele não se aplica a implementações mais recentes do .NET, incluindo o .NET 6 e versões posteriores.

O MDA (assistente para depuração gerenciada) de streamWriterBufferedDataLost é ativado quando um StreamWriter é gravado, mas o método Flush ou Close não é chamado posteriormente antes da destruição da instância do StreamWriter. Quando esse MDA está habilitado, o runtime determina se todos os dados armazenados em buffer ainda existem no StreamWriter. Se os dados armazenados em buffer existirem, o MDA será ativado. A chamada aos métodos Collect e WaitForPendingFinalizers pode forçar os finalizadores a serem executados. Caso contrário, os finalizadores serão executados em horários aparentemente arbitrários e, possivelmente, não na saída do processo. A execução explícita dos finalizadores com esse MDA habilitado ajudará a reproduzir esse tipo de problema de maneira mais confiável.

Sintomas

Um StreamWriter não grava os últimos 1-4 KB de dados em um arquivo.

Causa

O StreamWriter armazena os dados em buffer internamente, o que exige que o método Close ou Flush seja chamado para gravar os dados em buffer no armazenamento de dados subjacente. Se Close ou Flush não for chamado corretamente, os dados armazenados em buffer na instância StreamWriter poderão não ser gravados como esperado.

Veja a seguir um exemplo de um código mal escrito que esse MDA deverá capturar.

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

O código anterior ativará esse MDA de maneira mais confiável se uma coleta de lixo for disparada e, em seguida, suspensa até a conclusão dos finalizadores. Para rastrear esse tipo de problema, adicione o código a seguir ao final do método anterior em um build de depuração. Isso ajudará a ativar o MDA de maneira confiável, mas obviamente, não corrige a causa do problema.

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

Resolução

Chame Close ou Flush no StreamWriter antes de fechar um aplicativo ou qualquer bloco de códigos que tem uma instância de um StreamWriter. Um dos melhores mecanismos para fazer isso é criar a instância com um bloco using do C# (Using no Visual Basic), o que garantirá a invocação do método Dispose para o gravador, resultando no fechamento correto da instância.

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

O código a seguir mostra a mesma solução, usando try/finally em vez de using.

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

Se nenhuma dessas soluções puder ser usada (por exemplo, se um StreamWriter for armazenado em uma variável estática e não for possível executar o código facilmente ao final de seu tempo de vida), a chamada a Flush no StreamWriter após seu último uso ou a configuração da propriedade AutoFlush como true antes de seu primeiro uso deverá evitar esse problema.

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;
}

Efeito sobre o runtime

Esse MDA não tem nenhum efeito sobre o runtime.

Saída

Uma mensagem que indica que essa violação ocorreu.

Configuração

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

Confira também