internal byte[] GetLargeBuffer(int requiredSize, string tag)
{
requiredSize = this.RoundToLargeBufferMultiple(requiredSize);
var poolIndex = requiredSize / this.largeBufferMultiple - 1;
byte[] buffer;
if (poolIndex < this.largePools.Length)
{
if (!this.largePools[poolIndex].TryPop(out buffer))
{
buffer = new byte[requiredSize];
Events.Write.MemoryStreamNewLargeBufferCreated(requiredSize, this.LargePoolInUseSize);
if (this.LargeBufferCreated != null)
{
this.LargeBufferCreated();
}
}
else
{
Interlocked.Add(ref this.largeBufferFreeSize[poolIndex], -buffer.Length);
}
}
else
{
// Buffer is too large to pool. They get a new buffer.
// We still want to track the size, though, and we've reserved a slot
// in the end of the inuse array for nonpooled bytes in use.
poolIndex = this.largeBufferInUseSize.Length - 1;
// We still want to round up to reduce heap fragmentation.
buffer = new byte[requiredSize];
string callStack = null;
if (this.GenerateCallStacks)
{
// Grab the stack -- we want to know who requires such large buffers
callStack = PclExport.Instance.GetStackTrace();
}
Events.Write.MemoryStreamNonPooledLargeBufferCreated(requiredSize, tag, callStack);
if (this.LargeBufferCreated != null)
{
this.LargeBufferCreated();
}
}
Interlocked.Add(ref this.largeBufferInUseSize[poolIndex], buffer.Length);
return buffer;
}