DEV Community

Cristiano Rodrigues for Unhacked

Posted on

2

Economize memória e aumente o desempenho com o ArrayPool<T> do .NET

A alocação e desalocação de memória podem impactar negativamente o desempenho de uma aplicação. Especialmente em aplicações de alto desempenho, como servidores web, processamento de big data e jogos, a eficiência no gerenciamento de memória é fundamental para garantir uma execução suave e rápida. Felizmente, o dotnet oferece uma solução poderosa e pouco conhecida para otimizar a alocação de memória: o ArrayPool.

O que é o ArrayPool

O ArrayPool é uma classe que fornece uma maneira eficiente de alocar e reutilizar arrays, evitando a criação e desalocação excessiva de memória. Ele faz parte do namespace System.Buffers e está disponível nas versões do .NET Framework 4.5 e posteriores, bem como no .NET Core e no .NET 5.0 e versões posteriores. É uma classe thread-safe e apesar de sua eficiência comprovada, ainda é pouco utilizado pelos desenvolvedores, o que representa uma grande oportunidade de ganho de desempenho.

Como funciona o ArrayPool?

O ArrayPool gerencia um pool de arrays de um tipo específico T.
Ao invocar o ArrayPool é criado um bucket com 17 arrays com comprimentos de: 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288 e 1048576, conforme podemos observar nos trechos de códigos abaixo:

Shared

TlsOverPerCoreLockedStacksArrayPool

Utilities

A função GetMaxSizeForBucket calcula o tamanho máximo para um "bucket" (compartimento) com base no índice do compartimento, usando um deslocamento de bits à esquerda (<<). O operador de deslocamento de bits à esquerda (<<) desloca os bits de um valor para a esquerda, multiplicando o valor por 2 elevado à potência do número de posições de deslocamento. No caso do código, o valor 16 é deslocado para a esquerda pelo número de posições indicado pelo valor de "binIndex".

A linha "int maxSize = 16 << binIndex;" calcula o tamanho máximo do compartimento, onde o tamanho é igual a 16 multiplicado por 2 elevado à potência do valor de "binIndex". Isso implica que o tamanho do compartimento será multiplicado por 2 a cada incremento de "binIndex". Por exemplo, se "binIndex" for 0, o tamanho máximo será 16 (16 << 0 = 16); se "binIndex" for 1, o tamanho máximo será 32 (16 << 1 = 32); se "binIndex" for 2, o tamanho máximo será 64 (16 << 2 = 64), e assim por diante.

Quando você solicita uma instância do array usando o método Shared, ele retorna uma instância compartilhada. Em seguida, você pode usar o método Rent para obter um buffer que tenha, pelo menos, o comprimento solicitado. E, ao invés de desalocar o array quando não for mais necessário, você o devolve ao ArrayPool chamando o método Return.

A ideia é que, em vez de alocar e desalocar arrays repetidamente durante a execução de uma aplicação, o ArrayPool reutilize arrays previamente alocados sempre que possível. Isso reduz o tempo de execução e o consumo de recursos, especialmente em cenários em que muitos arrays pequenos precisam ser alocados e desalocados rapidamente.

// esqueleto do ArrayPool<T>, onde devemos substituir T pelo tipo

ArrayPool<T> pool = ArrayPool<T>.Shared;
var memory = pool.Rent(20000);
try
{
}
finally
{
  pool.Return(memory);
}
Enter fullscreen mode Exit fullscreen mode

Realizando o Benchmark

Utilizaremos um código muito comum nas aplicações dotnet, onde os desenvolvedores costumam trabalhar com listas para carregarem objetos de uma determinada classe.

Benchmark

Análise do Benchmark

O ArrayPool é mais eficiente trabalhando com arrays maiores, consegue ser 2 vezes mais rápido em alguns casos e com a menor alocação de memória.

Conclusão

O ArrayPool é uma ferramenta poderosa para otimizar a alocação de memória em aplicações de alto desempenho, e seu uso pode levar a uma execução mais suave e rápida. É importante que os desenvolvedores considerem sua utilização em cenários onde a eficiência no gerenciamento de memória é crítica, visando melhorar o desempenho e a escalabilidade de suas aplicações.

Speedy emails, satisfied customers

Postmark Image

Are delayed transactional emails costing you user satisfaction? Postmark delivers your emails almost instantly, keeping your customers happy and connected.

Sign up

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay