Runtime: Memory leak caused by use of ArrayPool<byte>.Shared in underlying libraries.

Created on 11 Dec 2017  路  3Comments  路  Source: dotnet/runtime

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.Shared implementation. Currently we're using a reflection hack to work around the issue.

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
            // ...
    }
area-System.Buffers enhancement tenet-performance

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:

  • Applications that don't want to trade memory for CPU
  • Applications where the default implementation doesn't work well in some specific case

All 3 comments

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:

  • Applications that don't want to trade memory for CPU
  • Applications where the default implementation doesn't work well in some specific case
Was this page helpful?
0 / 5 - 0 ratings

Related issues

matty-hall picture matty-hall  路  3Comments

omajid picture omajid  路  3Comments

v0l picture v0l  路  3Comments

noahfalk picture noahfalk  路  3Comments

chunseoklee picture chunseoklee  路  3Comments