protected override void Dispose(bool disposing) { // NB this method is called after ensuring that refcount is zero but before // cleaning the fields BufferPool <T> .Return(Array); base.Dispose(disposing); Pool.TryAdd(this); }
internal byte[] GetBlock() { var buffer = BufferPool <byte> .Rent(_blockSize); if (buffer.Length == _blockSize) { return(buffer); } BufferPool <byte> .Return(buffer, false); buffer = new byte[_blockSize]; return(buffer); }
protected override void Dispose(bool disposing) { var array = Interlocked.Exchange(ref _array, null); if (array != null) { _disposed = true; BufferPool <T> .Return(array); } if (disposing) { Pool.TryAdd(this); } }
internal void ReturnLargeBuffer(byte[] buffer, string tag) { if (buffer == null) { ThrowHelper.ThrowArgumentNullException("buffer"); return; } if (!IsLargeBufferMultiple(buffer.Length)) { BufferPool <byte> .Return(buffer); return; } var poolIndex = buffer.Length / _largeBufferMultiple - 1; 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 { Events.Write.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; Events.Write.MemoryStreamDiscardBuffer(Events.MemoryStreamBufferType.Large, tag, Events.MemoryStreamDiscardReason.TooLarge); ReportLargeBufferDiscarded(Events.MemoryStreamDiscardReason.TooLarge); } Interlocked.Add(ref _largeBufferInUseSize[poolIndex], -buffer.Length); //ReportUsageReport(_smallPoolInUseSize, _smallPoolFreeSize, LargePoolInUseSize, LargePoolFreeSize); ReportUsageReport(0, 0, LargePoolInUseSize, LargePoolFreeSize); }
internal override unsafe void Free(bool finalizing) { ThrowHelper.Assert(IsDisposed); var array = Interlocked.Exchange(ref _array, null); if (array != null) { ThrowHelper.DebugAssert(TypeHelper <T> .IsReferenceOrContainsReferences); if (!finalizing && !ExternallyOwned) { BufferPool <T> .Return(Unsafe.As <T[]>(array), clearArray : true); } } var pointer = Interlocked.Exchange(ref _pointer, IntPtr.Zero); if (pointer != IntPtr.Zero) { Mem.Free((byte *)pointer); BuffersStatistics.ReleasedNativeMemory.InterlockedAdd(_length); } // In PM either pointer or array, never both if (array == null && pointer == IntPtr.Zero) { string msg = "Tried to free already freed PrivateMemory"; #if DEBUG ThrowHelper.ThrowInvalidOperationException(msg); #endif Trace.TraceWarning(msg); return; } ClearFields(); // We cannot tell if this object is pooled, so we rely on finalizer // that will be called only if the object is not in the pool. // But if we tried to pool the buffer to RMP but failed above // then we called GC.SuppressFinalize(this) // and finalizer won't be called if the object is dropped from ObjectPool. // We have done buffer clean-up job and this object could die normally. if (!finalizing) { ObjectPool.Return(this); } }
internal void ReturnBlocks(List <byte[]> blocks, string tag) { if (blocks == null) { ThrowHelper.ThrowArgumentNullException("blocks"); return; } if (blocks.Count > 0) { foreach (var block in blocks) { if (block == null || block.Length != BlockSize) { ThrowHelper.ThrowArgumentException("blocks contains buffers that are not BlockSize in length"); } BufferPool <byte> .Return(block, false); } } ReportUsageReport(0, 0, LargePoolInUseSize, LargePoolFreeSize); }
internal override unsafe void Free(bool finalizing) { ThrowHelper.Assert(IsDisposed); var array = Interlocked.Exchange(ref _array, null); if (array != null) { ThrowHelper.DebugAssert(TypeHelper <T> .IsReferenceOrContainsReferences); // Even if we are finalizing the fields are not collected, because this // object is reachable and hence the fields are reachable. if (!ExternallyOwned) { BufferPool <T> .Return(Unsafe.As <T[]>(array), clearArray : true); } } var pointer = Interlocked.Exchange(ref _pointer, IntPtr.Zero); if (pointer != IntPtr.Zero) { // TODO Switch to mimalloc after updating to new release Marshal.FreeHGlobal(pointer); // Mem.Free((byte*) pointer); BuffersStatistics.ReleasedNativeMemory.InterlockedAdd(_length); } // In PM either pointer or array, never both if (array == null && pointer == IntPtr.Zero) { string msg = "Tried to free already freed PrivateMemory"; #if DEBUG ThrowHelper.ThrowInvalidOperationException(msg); #endif Trace.TraceWarning(msg); return; } ClearFields(); // This instance is clean now. // If we are finalizing then resurrect it by placing it to the pool. // If we are disposing then also add to the pool. var pooled = ObjectPool.Return(this); // If we were finalizing but resurrected then the next time // the instance is dropped the finalizer will not run, // therefore we must re-register. if (pooled && finalizing) { GC.ReRegisterForFinalize(this); } // If we cannot pool the instance and not running from finalizer // then the reference is dropped and finalizer could re-run. // In that case suppress it. // If not pooled and finalizing then the job is done. if (!pooled && !finalizing) { GC.SuppressFinalize(this); } }