So I'm optimizing a C# program which uses byte arrays very very frequently, I wrote a kind of recycle pool thing to reuse arrays which had to be collected by GC. Like that:
public class ArrayPool<T>
{
private readonly ConcurrentDictionary<int, ConcurrentBag<T[]>> _pool;
public ArrayPool()
{
_pool = new ConcurrentDictionary<int, ConcurrentBag<T[]>>();
}
public ArrayPool(int capacity)
{
_pool = new ConcurrentDictionary<int, ConcurrentBag<T[]>>(4, capacity);
for (var i = 1; i <= capacity; i++)
{
_pool.TryAdd(i, new ConcurrentBag<T[]>());
}
}
public T[] Alloc(int capacity)
{
if (capacity < 1)
{
return null;
}
if (_pool.ContainsKey(capacity))
{
var subpool = _pool[capacity];
T[] result;
if (subpool != null) return subpool.TryTake(out result) ? result : new T[capacity];
subpool = new ConcurrentBag<T[]>();
_pool.TryAdd(capacity, subpool);
_pool[capacity] = subpool;
return subpool.TryTake(out result) ? result : new T[capacity];
}
_pool[capacity] = new ConcurrentBag<T[]>();
return new T[capacity];
}
public void Free(T[] array)
{
if (array == null || array.Length < 1)
{
return;
}
var len = array.Length;
Array.Clear(array, 0, len);
var subpool = _pool[len] ?? new ConcurrentBag<T[]>();
subpool.Add(array);
}
}
and I also wrote some code to test its performance:
const int TestTimes = 100000;
const int PoolCapacity = 1000;
public static ArrayPool<byte> BytePool;
static void Main()
{
BytePool = = new ArrayPool<byte>(PoolCapacity);
var watch = Stopwatch.StartNew();
for (var i = 1; i <= TestTimes; i++)
{
var len = (i % PoolCapacity) + 1;
var array = new byte[len];
}
watch.Stop();
Console.WriteLine("Traditional Method: {0} ms.", watch.ElapsedMilliseconds);
watch = Stopwatch.StartNew();
for (var i = 1; i <= TestTimes; i++)
{
var len = (i % PoolCapacity) + 1;
var array = BytePool.Alloc(len);
BytePool.Free(array);
}
watch.Stop();
Console.WriteLine("New Method: {0} ms.", watch.ElapsedMilliseconds);
Console.ReadKey();
}
I thought it should be faster if the program could reuse memory instead of malloc them every time, but it turns out that my code is about 10 times slower than before:
Traditional Method: 31 ms. New Method: 283 ms.
So is it true that resuing arrays could increase performance in C#? If true, why my code is so slow? Is there better way to reuse arrays?
Any advice would be appreciated.Thank you.
malloc
in C# has virtually zero cost, so it’s not surprising that your complex, manual memory management method performs worse. – Thunder