Introduction
There are situations that an array is created over and over again. It is perfectly normal but it creates many temporary objects on the heap. More heap objects means more allocated memory. More allocated memory means more GC overhead. There is, however,
a simple and elegant solution to the problem and it is called ArrayPool.
ArrayPool
ArrayPool is class in a System.Buffers namespace that: “Provides a resource pool that enables reusing instances of type T[].” Using ArrayPool is quite straightforward and in most cases is limited to the Rent and Return methods. First method (as name suggests) rents an array from the pool and the latter one returns the array if it is not needed anymore. There is a great speech about high-performance patterns in C# here (pooling starts at 9:50).
Example
Let’s consider the following ArrayExecutor
class:
public class ArrayExecutor
{
private readonly int _size;
private readonly Random _random;
public ArrayExecutor(int size)
{
_random = new Random();
_size = size;
}
public void ArrayLoop()
{
var array = new int[_size];
for (int i = 0; i < _size; i++)
array[i] = _random.Next(100);
var minMax = new int[2]
{
array.Min(), array.Max()
};
Process(minMax);
}
public void ArrayPoolLoop()
{
var array = ArrayPool<int>.Shared.Rent(_size);
for (int i = 0; i < _size; i++)
array[i] = _random.Next(100);
var minMax = new int[2]
{
array.Min(), array.Max()
};
Process(minMax);
ArrayPool<int>.Shared.Return(array);
}
private void Process(int[] array)
{
// some computations here
}
}
The class consists of two public methods: ArrayLoop
and ArrayPoolLoop
. First method uses the new() operator to create an array, whereas the latter uses ArrayPool<int>.Shared
. Shared is a property of the ArrayPool<T> that provides a default implementation of the ArrayPool. Once the array is created we populated it with some random numbers. Then we calculate min and max and we don’t need the array anymore. As you can see, the ArrayPoolLoop
rents an array and then returns it to the pool.
NOTE: the Rent
method returns an array that is at least the requested length! (e.g. Rent(10) returns an array 16 elements)
Benchmark
Let’s look at the following benchmark result:
This time the last column is crucial for us. As you can see, allocations are tremendously greater for the ArrayLoop method. The ArrayPoolLoop method barely allocates memory.
Summary
To sum up, ArrayPool is definitely useful in terms of reducing allocation. Reducing allocations is an important topic in the .NET environment. It might be beneficial to be aware of the possible solutions in terms of reducing memory consumption, hence I highly recommend to do some experiments with the ArrayPool.
As always I’ve prepared an example and you can find it on my github, project: arraypool, benchmark project: arraypool-benchmark.
I encourage you to go through the code, debug it and try to test your own scenarios.
Have a nice day, bye!
Be First to Comment