Our application eventually runs out of memory after a few days of running. We've traced down the majority of heap usage to buffers allocated by the DefaultArrayPool.
We would like the ability to turn off or replace the ArrayPool
Workaround:
public class NullArrayPool<T> : ArrayPool<T>
{
public override T[] Rent(int minimumLength)
{
return new T[minimumLength];
}
public override void Return(T[] array, bool clearArray = false)
{
}
}
public static class ArrayPoolUtil
{
public static void SetShared<T>(ArrayPool<T> arrayPool)
{
var flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
var q = from field in typeof(ArrayPool<T>).GetTypeInfo().GetFields(flags)
where field.IsStatic && (field.Name == "s_sharedInstance" || field.Name == "<Shared>k__BackingField")
select field;
var target = q.FirstOrDefault();
if (target == null) throw new InvalidOperationException("Unable to set ArrayPool.Shared");
target.SetValue(null, arrayPool);
}
}
public static void Main()
{
ArrayPoolUtil.SetShared(new NullArrayPool<byte>()); // works around memory leak
// ...
}
Yes, ArrayPool can keep a lot of unused memory alive.
I think a better fix would be to make GC aware of it and allow it to flush it.
https://github.com/dotnet/coreclr/issues/7747
It would be great to have a better implementation that responded to memory pressure. I look forward to that happening.
That said... it would still be useful to swap out the implementation for the following reasons:
Closing as addressed by https://github.com/dotnet/coreclr/pull/17078.
Most helpful comment
It would be great to have a better implementation that responded to memory pressure. I look forward to that happening.
That said... it would still be useful to swap out the implementation for the following reasons: