As previously I felt like browsing around the .NET Core source code again, with the aim to pick up some things.
I ran into a class I didn't know: ArrayPool.
Which, according to the docs:
- Provides a resource pool that enables reusing instances of type T[].
Purpose of ArrayPool?
If you have some code that needs to use arrays frequently, you may be "newing" them up a lot:
var buffer = new MyObject[](1024);
If you only keep the array in memory for a short time. And if you do this a lot. Know that instantiating a new
array can be costly: .NET has to find some memory to allocate and reserve it for your array. The garbage collector then later needs to free it up again, ...
If speed and resource usage is a concern, you could benefit from re-using buffers you no longer use elsewhere.
This can be tricky, especially in multi threaded environments such as web applications.
This is where the ArrayPool
can help. You tell it to reserve some arrays, and in a threadsafe manner you can rent one out when you need it.
Threasafe so that if you are using an array from the pool you can be sure no other thread is using that same array.
Interesting things in the code ...
You can find the source code here: https://github.com/dotnet/corefx/blob/master/src/System.Buffers/src/System/Buffers/ArrayPool.cs
For reference, the exact version I'm looking at has this permanent link: https://github.com/dotnet/corefx/blob/e425ca81ce808229346178bff57811159c007fa4/src/System.Buffers/src/System/Buffers/DefaultArrayPool.cs
abstract class
The ArrayPool is declared as an abstract class
:
public abstract class ArrayPool<T>
This means the class contains some unimplemented methods, that must be implemented by any class that inherits from ArrayPool<T>
.
It also means you cannot created a new instance of the class:
// Won't work:
var myPool = new ArrayPool<int>();
.NET does offer a default implementation, which can be reached via the Shared
property:
// Will work:
var myPool = ArrayPool<int>.Shared;
// Rent an array of 100 ints from the pool:
var rentedArray = myPool.Rent(100);
That property is a shared
property on the class. This is a way to offer a default implementation of the an abstract class. Also, it's another new
that can be avoided.
It's also possible to set create a new pool using: ArrayPool<T>.Create
. This creates a pool with a size you can set yourself.
Aggresive Inlining
Apart from a fashionable sport I enjoyed when I was younger, aggresive inlining tells the compiler to "inline" a method.
public static ArrayPool<T> Shared
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return Volatile.Read(ref s_sharedInstance) ?? EnsureSharedCreated(); }
}
Here, the code tells the JIT compiler to "inline" the get method. This means, in the compiled code, the method won't be called, but the code inside the method will be put directly into your compiled assembly.
Note this also applies to your code calling the assemblies of .NET. The JIT (Just-in-Time) compiler from the CLR (runtime) can inline these methods.
These are really optimizations you normally don't have to worry about.
Conclusion
In all the .NET Core code, you frequently encounter some of these optimizations, such as the AggresiveInlining
we saw above. It's part of an ongoing effort that focusses on improving the efficiency of .NET Core.
The ArrayPool class could come in handy if you're creating and destroying a lot of arrays quickly and worry about the impact on performance.