DEV Community

Cristiano Rodrigues for Unhacked

Posted on • Updated on

Reduzindo drasticamente o uso de memória com o Log

O registro de logs desempenha um papel fundamental no monitoramento e depuração de aplicações dotnet. No entanto, o uso inadequado do log pode impactar negativamente o desempenho das aplicações.

É comum espalhar chamadas para a escrita de logs em todo o código, frequentemente utilizando interpolação de strings para facilitar a sua criação. No entanto, raramente avaliamos se essa abordagem é a mais eficiente.

Analisando o benchmark do método LogInformation

Para ilustrar o impacto da alocação de memória, examinaremos o benchmark do método LogInformation, existente no Logger comum que é aquele que utiliza os métodos de extensão da interface ILogger. O código de teste é simples e comumente encontrado em aplicações em produção.

[Benchmark(Baseline = true)]
public void LogInformationComStringInterpolation()
{
    _logger.LogInformation($"Pedido {_pedido} gerado com sucesso!");
}
Enter fullscreen mode Exit fullscreen mode

Benchmark com interpolação de strings

Ao executar o benchmark com interpolação de strings, observamos uma alocação de 80 bytes. Parece ser uma quantidade insignificante, mas quando repetimos essa chamada em um loop de 100.000 iterações, como em uma importação de arquivos, a alocação totaliza 7,63MB. É uma quantidade considerável de memória utilizada apenas para escrever logs.

benchLogInformation

benchLogInformation100k

Alocação de memória mesmo com LogLevel definido como Warning

Surpreendentemente, mesmo definindo o LogLevel como Warning, a alocação de memória continua a mesma (7,63MB). Isso pode ser alarmante, especialmente considerando a presença de outras chamadas de log, como LogDebug, LogTrace e LogInformation, espalhadas pelo código.

benchLogInformation100kWarning

Reduzindo a alocação de memória com "String Template"

Uma abordagem para reduzir a alocação de memória é utilizar o formato de "String Template" em vez de interpolação de strings. Ao aplicar essa alteração, a alocação de memória é reduzida para 56 bytes em um único teste. Realizando o mesmo teste com 100.000 iterações, a alocação de memória continua menor em comparação à interpolação de strings.

benchLogInformationStringTemplate

benchLogInformationStringTemplate100K

Evitando alocação de memória com verificação do LogLevel

Podemos evitar a alocação de memória ao verificar se o LogLevel está habilitado antes de realizar a chamada para o log. Essa abordagem resolve o problema quando desejamos aumentar o LogLevel em produção. No entanto, ainda ocorre alocação de memória quando precisamos executar o LogInformation em produção. Embora o uso de "String Template" possa reduzir o consumo, não é possível eliminá-lo completamente.

benchLogInformationComIf100K

[Benchmark(Baseline = true)]
public void LogInformationComStringInterpolation()
{
    for (int i = 0; i < 100_000; i++)
    {
        if (_logger.IsEnabled(LogLevel.Information))
        {
            _logger.LogInformation($"Pedido {_pedido} gerado com sucesso!");
        }
    }
}

[Benchmark]
public void LogInformationComStringTemplate()
{
    for (int i = 0; i < 100_000; i++)
    {
        if (_logger.IsEnabled(LogLevel.Information))
        {
            _logger.LogInformation("Pedido {Pedido} gerado com sucesso!", _pedido);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Conclusão e próximos passos

É essencial compreender o motivo das alocações de memória no Logger e explorar abordagens para evitá-las. No próximo artigo, explicaremos os motivos das alocações e o método para diminuir as alocações de memória ao utilizar logs.

O teste a seguir apresenta uma otimização, na qual nenhuma alocação de memória é necessária durante a escrita dos logs.

benchLogInformationCom100KOtimizado

Mantenha-se atualizado e não perca a continuação deste conteúdo!

Top comments (0)