/// <summary> /// Returns the buffer to the large pool /// </summary> /// <param name="buffer">The buffer to return.</param> /// <param name="tag">The tag of the stream returning this buffer, for logging if necessary.</param> /// <exception cref="ArgumentNullException">buffer is null</exception> /// <exception cref="ArgumentException"> /// buffer.Length is not a multiple/exponential of LargeBufferMultiple (it did not /// originate from this pool) /// </exception> internal void ReturnLargeBuffer(byte[] buffer, string tag) { if (buffer == null) { throw new ArgumentNullException(nameof(buffer)); } if (!IsLargeBufferSize(buffer.Length)) { throw new ArgumentException( string.Format("buffer did not originate from this memory manager. The size is not {0} of ", UseExponentialLargeBuffer ? "an exponential" : "a multiple") + LargeBufferMultiple); } var poolIndex = GetPoolIndex(buffer.Length); if (poolIndex < _largePools.Length) { if ((_largePools[poolIndex].Count + 1) * buffer.Length <= MaximumFreeLargePoolBytes || MaximumFreeLargePoolBytes == 0) { _largePools[poolIndex].Push(buffer); Interlocked.Add(ref _largeBufferFreeSize[poolIndex], buffer.Length); } else { EventsWriter.MemoryStreamDiscardBuffer(Events.MemoryStreamBufferType.Large, tag, Events.MemoryStreamDiscardReason.EnoughFree); ReportLargeBufferDiscarded(Events.MemoryStreamDiscardReason.EnoughFree); } } else { // This is a non-poolable buffer, but we still want to track its size for inuse // analysis. We have space in the inuse array for this. poolIndex = _largeBufferInUseSize.Length - 1; EventsWriter.MemoryStreamDiscardBuffer(Events.MemoryStreamBufferType.Large, tag, Events.MemoryStreamDiscardReason.TooLarge); ReportLargeBufferDiscarded(Events.MemoryStreamDiscardReason.TooLarge); } Interlocked.Add(ref _largeBufferInUseSize[poolIndex], -buffer.Length); ReportUsageReport(_smallPoolInUseSize, _smallPoolFreeSize, LargePoolInUseSize, LargePoolFreeSize); }
/// <summary> /// Returns the blocks to the pool /// </summary> /// <param name="blocks">Collection of blocks to return to the pool</param> /// <param name="tag">The tag of the stream returning these blocks, for logging if necessary.</param> /// <exception cref="ArgumentNullException">blocks is null</exception> /// <exception cref="ArgumentException">blocks contains buffers that are the wrong size (or null) for this memory manager</exception> internal void ReturnBlocks(ICollection <byte[]> blocks, string tag) { if (blocks == null) { throw new ArgumentNullException(nameof(blocks)); } var bytesToReturn = blocks.Count * BlockSize; Interlocked.Add(ref _smallPoolInUseSize, -bytesToReturn); foreach (var block in blocks) { if (block == null || block.Length != BlockSize) { throw new ArgumentException("blocks contains buffers that are not BlockSize in length"); } } foreach (var block in blocks) { if (MaximumFreeSmallPoolBytes == 0 || SmallPoolFreeSize < MaximumFreeSmallPoolBytes) { Interlocked.Add(ref _smallPoolFreeSize, BlockSize); _smallPool.Push(block); } else { EventsWriter.MemoryStreamDiscardBuffer(Events.MemoryStreamBufferType.Small, tag, Events.MemoryStreamDiscardReason.EnoughFree); ReportBlockDiscarded(); break; } } ReportUsageReport(_smallPoolInUseSize, _smallPoolFreeSize, LargePoolInUseSize, LargePoolFreeSize); }