Description
To give users with high perf scenarios more flexibility for array allocations I propose to add a new API in the GC class.
Rationale
Below are mechanisms we would like to support for high perf scenarios
- coreclr dotnet/runtime#20704;
- choose whether you want to allocate the object as a gen0 object or in the old generation;
- choose whether you want to pin the object you are requesting to allocate;
I am also thinking of exposing the large object size threshold as a config to users and this API along with that config should help a lot with solving the LOH perf issues folks have been seen.
Proposed APIs
class GC
{
// generation: -1 means to let GC decide (equivalent to regular new T[])
// 0 means to allocate in gen0
// GC.MaxGeneration means to allocate in the oldest generation
//
// pinned: true means you want to pin this object that you are allocating
// otherwise it's not pinned.
//
// alignment: only supported if pinned is true.
// -1 means you don't care which means it'll use the default alignment.
// otherwise specify a power of 2 value that's >= pointer size
// the beginning of the payload of the object (&array[0]) will be aligned with this alignment.
static T[] AllocateArray<T>(int length, int generation=-1, bool pinned=false, int alignment=-1)
{
// calls the new AllocateNewArray fcall.
return AllocateNewArray(typeof(T).TypeHandle.Value, length, generation, pinned, clearMemory: true);
}
// Skips zero-initialization of the array if possible. If T contains object references,
// the array is always zero-initialized.
static T[] AllocateUninitializedArray<T>(int length, int generation=-1, bool pinned=false, int alignment=-1)
{
return AllocateNewArray(typeof(T).TypeHandle.Value, length, generation, pinned, clearMemory: false);
}
}
Restrictions
Only array allocations are supported via this API
Note that I am returing a T[] because this only supports allocating large arrays. it's difficult to support allocating a non array object since you'd need to pass in args for constructors and it's rare for a non array object to be large anyway. I have seen large strings but these are unlikely used in high perf scenarios. and strings also have multiple constructors...we can revisit if string is proven to be necessary.
Minimal size supported
Even though the size is no longer restricted to >= LOH threshold, I might still have some sort of size limit so it doesn't get too small. I will update this when I have that exact size figured out.
Perf consideration
Cost of getting the type
The cost of "typeof(T).TypeHandle.Value" should be dwarfed by the allocation cost of a large object; however in the case of allocating a large object without clearing memory, the cost may show up (we need to do some profiling). If that's proven to be a problem we can implement coreclr dotnet/corefx#5329 to speed it up.
Pinning
We'll provide a pinned heap that are only for objects pinned via this API. So this is for scenarios where you
- have control over the allocation of the object you want to pin and
- want to pin it as long as it's alive
Since we will not be compacting this heap fragmentation may be a problem so as with normal pinning, it should be use it with caution.
I would like to limit T for the pinning case to contain no references. But I am open to discussion on whether it's warranted to allow types with references.