Gerenciamento de Memória e Melhorias de Performance em .NET

Alan Nunes
Comunidade XP
3 min readMar 7, 2022

--

Neste artigo irei mostrar algumas melhorias que podemos aplicar no nosso código para dar aquele boost de performance em nossa aplicação. Veremos também alguns conceitos sobre gerenciamento de memória.

Gerenciamento de Memória

Antes de tudo, precisamos entender como funciona o gerenciamento de memória de um código, esse será o ponto chave.

Unmanaged Memory (Memória Não Gerenciada)

Quando um código é unmanaged memory significa que todos recursos alocados na memória durante a execução do programa é liberado explicitamente pelo programador, ou seja, você precisa escrever código para liberar esse recurso.
Explicando de forma simples, você mesmo ficará incubido de desalocar os objetos da memória que não estão sendo mais utilizados. Pseudocódigo:

// Aloca o objeto na memória
pessoa = new Pessoa();
// Desaloca o objeto da memória explicitamente
desalocar_da_memoria(pessoa);

Managed Memory (Memória Gerenciada)

Quando um código é managed memory significa que o programador não precisa desalocar os rescursos da memória, pois existe um intermediador que realiza esse trabalha sujo para ele.
Esse intermediador é o Garbage Collector, outro ponto chave para nós nesse artigo. Pseudocódigo:

// Aloca o objeto na memória
pessoa = new Pessoa();

Não controlamos a desalocação dos recursos, pois delegamos essa tarefa ao Garbage Collector.

Garbage Collector

O Coletor de Lixos é responsável por desalocar recursos da memória que não estão sendo mais utilizados.

Sempre que o coletor de lixos achar necessário, ele iniciará a coleta e nós não controlamos isso. Aliás podemos controlar sim, mas isso é um assunto para um próximo artigo.

Suspensão

Toda vez que o Garbage Collector faz a coleta de lixos, ele suspende sua aplicação, ou seja, ela fica congelada. É nesse momento que podemos ter problemas de performance.

E como funciona o .NET?

Os códigos escritos em .NET são gerenciados, então significa que o Garbage Collector se incube de coletar todos os lixos da memória.

Evite Excesso de Alocação

O Excesso de alocação de recursos na memória pode causar uma grande quantidade de ativação ao Garbage Collection, que irá suspender sua aplicação a cada chamada. Essa suspensão/congelamento é muito rápida, porém quando ocorre diversas vezes a perda de performance é enorme.

Exemplo

Classe Calculator.cs
Código com excesso de alocação

O código parece inofensivo, mas perceba que a cada iteração, estamos instanciando um novo objeto, ou seja, alocando um novo recurso na memória.

Execução com excesso de alocação

O código executou em 8810 ms e houve 7651 suspensões na nossa aplicação.

Agora vamos aplicar uma simples melhoria, que dará uma grande diferença na execução da aplicação. Ao invés de alocar o recurso a cada iteração, vamos alocá-lo apenas uma vez.

Código com melhoria
Exemplo com melhoria de performance

Com essa mudança simples, o tempo de execução caiu 63%, executando em 3290 ms e sem nenhuma suspensão na aplicação.

Bônus

O Garbage Collection possui três gerações (gen 0, gen 1 e gen2) e os recursos alocados na memória de curta duração ficam na geração 0, os que permanecem por mais tempo na memória, ficam na geração 1 e os de longa duração na geração 2. A geração 0 é visitada com maior frequência pelo coletor de lixos e toda vez que um recurso não é coletado, ele é promovido para a próxima geração.

Acesse o exemplo, pelo GitHub:

Referências

Este artigo veio de uma inspiração de um excelente vídeo da Examia Co: link video.

--

--