C# - Algumas dicas para melhorar o desempenho
Hoje veremos mais dicas para melhorar o desempenho do seu código C#. |
Se você deseja usar C# em aplicativos de desempenho crítico, as seguintes frases também devem entrar em sua mente: desempenho, velocidade e uso de memória.
Para te ajudar neste objetivo a seguir temos algumas dicas:
1. Evite o Coletor de Lixo ou Garbage Collector
Em uma aplicação
.NET, memória e desempenho estão muito ligados. O mau gerenciamento de memória
pode prejudicar o desempenho de várias maneiras. Um desses efeitos é chamado
GC Pressure ou Memory Pressure.
A pressão do GC (pressão do coletor de lixo) é quando o GC não acompanha as
desalocações de memória. Quando o GC é pressionado, ele passará mais tempo
coletando lixo, e essas coletas virão com mais frequência. Quando seu aplicativo
gasta mais tempo coletando lixo, ele gasta menos tempo executando código,
prejudicando diretamente o desempenho.
Evitar a coleta de lixo ajuda a manter altos níveis de desempenho, além de otimizar o uso de memória.
Para isso você pode por exemplo definir a capacidade inicial para coleções dinâmicas, usar Structs ou Records ao invés de classes quando isso for possível, usar StringBuilder com parcimônia, evitar o uso de Finalizers, usar ArrayPool para arrays grandes, etc.
2. Utilizar StackAllocators
Se seu aplicativo estiver fazendo muita alocação de memória, você poderá obter
melhor desempenho evitando o custo de liberar e alocar memória por conta
própria.
Você pode conseguir isso movendo para cima e para baixo em sua pilha até encontrar um bloco não utilizado e, em seguida, marcá-lo para reutilização. Um alocador baseado em pilha faz exatamente isso. Ele aloca memória de uma região chamada pilha sobre a qual novos blocos são colocados quando blocos liberados são encontrados.
Os alocadores de pilha podem ser mais eficientes do que os alocadores de heap, pois não precisam realizar nenhuma sincronização ou alocação de heap. Isso pode ser especialmente importante para aplicativos que precisam ser altamente eficientes, como jogos ou aplicativos em tempo real.
A palavra-chave StackAlloc em C# permite alocação e desalocação muito rápidas de memória não gerenciada. Ou seja, as classes não funcionarão, mas os primitivos, structs e arrays são suportados.
No geral, os alocadores de pilha são uma boa escolha para aplicativos que precisam ser altamente eficientes e que precisam de um alto grau de controle sobre o gerenciamento de memória. No entanto, eles não são adequados para todos os aplicativos e é importante considerar as desvantagens antes de usá-los.
3. Não reutilize referências de objetos
Este é um erro muito comum entre programadores iniciantes em C# : em vez de
limpar um objeto e liberar sua memória quando não for mais necessário, eles
simplesmente continuam usando até que não haja mais memória disponível.
Isso pode ser especialmente perigoso em aplicativos de servidor em que muitos
programas compartilham um servidor; a referência de objeto vazada de um programa
pode derrubar todos os outros programas que usam esse servidor.
Para evitar a criação de referências vazadas, defina explicitamente seus objetos como null quando terminar com eles — ou certifique-se de criar apenas quantas referências forem necessárias.
Object object1 =
new Object(); Object object2 = object1; // object1 e object2 agora se referem ao mesmo objeto object1 = null; // object1 não é mais usado mas não será desalocado // porque o object2 ainda faz referência a ele |
Para evitar vazamentos de memória, é importante nunca reutilizar referências de objetos. Em vez disso, você deve criar novas referências para objetos sempre que precisar usá-los.
Aqui está um exemplo de como criar uma nova referência para um objeto:
// Este código não vai criar uma
falha na memória Object object1 = new Object(); Object object2 = new Object(); // object1 e object2 agora se referem a objetos diferentes |
Ao seguir essas diretrizes, você pode ajudar a garantir que seu código não tenha vazamentos de memória.
4. Evite o mapeamento de memória (para
arquivos/sistemas de arquivos grandes)
Uma armadilha ao usar os métodos File.ReadAllText() ou
File.ReadAllLines() do C# é que eles carregam todo o conteúdo na memória
imediatamente. Isso pode causar gargalos de desempenho se você estiver lidando
com arquivos muito grandes e/ou subsistemas de armazenamento lentos, como discos
rígidos.
Uma maneira de contornar isso é usar um arquivo mapeado na memória, que cria espaço virtual na memória que se parece com um arquivo em disco.
Aqui estão algumas alternativas ao mapeamento de memória para arquivos ou sistemas de arquivos grandes:
5. Evite serialização/desserialização desnecessária
A plataforma .NET fornece recursos de serialização e desserialização de
objetos prontos para uso. O mesmo vale para várias linguagens .NET principais,
como C#, F# e Visual Basic .NET. No entanto, em determinadas circunstâncias,
essas funções podem causar problemas de desempenho significativos em seu
aplicativo.
Isso é
particularmente verdadeiro quando uma quantidade não trivial de dados precisa
ser serializada ou desserializada.
Se você estiver usando esses recursos regularmente, é importante entender como
eles funcionam para que você possa selecionar uma estratégia apropriada para
processar seus dados.
Dê preferência para usar a classe System.Text.Json para realizar essas operações, esta nova biblioteca esta integrada ao framework e elimina a a necessidade de dependências externas para lidar com JSON. É uma biblioteca leve que se concentra em funcionalidade e desempenho simples.
6. Mantenha o JIT afastado dos métodos não utilizados
O compilador Just-In-Time (JIT) é um processo que
lê o CIL e o traduz em código nativo. Ao construir um aplicativo, você não quer
que o JIT compile todas as suas classes — principalmente se elas forem usadas
apenas uma ou várias vezes na inicialização. Ao compilar apenas o que é
necessário quando necessário, você pode fazer seu aplicativo iniciar muito mais
rápido!
Existem várias maneiras de garantir que sua inicialização seja mais rápida e uma
delas é usando Reflection : Remova métodos não
utilizados desses objetos usando System.Reflection.Emit
que
contém classes que permitem a um compilador
ou uma ferramenta emitir metadados e MSIL
(Microsoft Intermediate Language) e se desejar gerar um arquivo PE no
disco.
7. Faça medições no modo de produção em vez do modo
Debug
Em muitas linguagens de programação, os aplicativos são executados em um modo de
depuração especial que permite aos desenvolvedores fazer coisas como definir
pontos de interrupção e imprimir mensagens de depuração. Essa é uma ótima
maneira de os desenvolvedores testarem seu código enquanto o desenvolvem — e
durante o desenvolvimento é essencial. Mas depois de terminar a codificação,
você deve voltar ao modo de produção antes que seu aplicativo seja liberado.
A execução do seu aplicativo no modo de produção elimina aquelas linhas extras
de código que são essenciais apenas durante o desenvolvimento.
8. Utilize um ofuscador de código
Outra última maneira para otimizar melhor sua aplicação .NET é usar um
.NET Obfuscator.
Isso ajudará você a otimizar fortemente seu aplicativo e obterá um aplicativo protegido, evitando descompilação e engenharia reversa.
A seguir vou deixar uma lista de alguns ofuscadores de códigos:
Eazfuscator.NET (free)
.NET Obfuscator (free)
Dotnet Stuff (free)
Aveloy (free)
Para obter uma relação maior e com mais detalhes veja o link : https://github.com/NotPrab/.NET-Obfuscator
E estamos conversados.
"Ainda que eu fale as línguas dos homens e dos anjos,
se não tiver amor, serei como o sino que ressoa ou como o prato que retine."
I Coríntios 13:1
Referências:
ASP .NET - Gerando QRCode com a API do Google
C# 9.0 - Instruções de nível superior
ASP.NET Core Web API - Apresentando API Analyzers
ASP.NET Core - Usando o token JWT com o Swagger
Gerando a documentação da Web API com Swagger