protected override void Dispose(bool disposing) { // disposing == false when finilizing and detected that non pooled if (disposing) { var pool = Pool; if (pool != null) { pool.ReturnInternal(this, clearMemory: false); // pool calls Dispose(false) is a bucket is full return; } // not pooled, doing finalization work now GC.SuppressFinalize(this); } Debug.Assert(!_isPooled); _poolIdx = default; AtomicCounter.Dispose(ref CounterRef); _isNativeWithHeader = false; CounterRef = AtomicCounter.CountMask; ClearAfterDispose(); // Dispose destructs this object and native buffer _offHeapBuffer.Dispose(); // set all to default, increase chances to detect errors _offHeapBuffer = default; }
protected override void Dispose(bool disposing) { if (ExternallyOwned) { ThrowHelper.ThrowNotSupportedException(); } if (disposing) { var pool = Pool; if (pool != null) { pool.ReturnInternal(this, clearMemory: !TypeHelper <T> .IsPinnable); // pool calls Dispose(false) if a bucket is full return; } // not pooled, doing finalization work now GC.SuppressFinalize(this); } // Finalization AtomicCounter.Dispose(ref CounterRef); Debug.Assert(!_isPooled); _poolIdx = default; // we still could add this to the pool of free pinned slices that are backed by an existing slab var pooledToFreeSlicesPool = _slicesPool.Return(this); if (pooledToFreeSlicesPool) { return; } var array = Interlocked.Exchange(ref _array, null); if (array != null) { ClearAfterDispose(); Debug.Assert(_handle.IsAllocated); #pragma warning disable 618 _slab.Decrement(); _handle.Free(); #pragma warning restore 618 } else { ThrowDisposed <ArrayMemorySlice <T> >(); } Debug.Assert(!_handle.IsAllocated); }
private static ObjectPool <PrivateMemory <T> > CreateObjectPool() { var op = new ObjectPool <PrivateMemory <T> >(() => { var pm = new PrivateMemory <T>(); AtomicCounter.Dispose(ref pm.CounterRef); return(pm); }, Settings.PrivateMemoryPerCorePoolSize ?? PerCorePoolSize); // Need to touch these fields very early in a common not hot place for JIT static // readonly optimization even if tiered compilation is off. // Note single & to avoid short circuit. if (AdditionalCorrectnessChecks.Enabled & TypeHelper <T> .IsReferenceOrContainsReferences) { ThrowHelper.Assert(!op.IsDisposed); } return(op); }
public RetainableMemoryPool(Func <RetainableMemoryPool <T>, int, RetainableMemory <T> > factory, int minLength = DefaultMinBufferLength, int maxLength = DefaultMaxBufferLength, int maxBuffersPerBucketPerCore = DefaultMaxNumberOfBuffersPerBucketPerCore, int maxBucketsToTry = 2, bool rentAlwaysClean = false) { if (factory == null) { throw new ArgumentNullException(nameof(factory)); } lock (KnownPools) { // Start from 2, other code depends on the first 2 items being null. // pool idx == 0 is always null which means a buffer is not from pool // pool idx == 1 means a buffer is from default pool, e.g. static array pool for (int i = 2; i < KnownPools.Length; i++) { if (KnownPools[i] == null) { PoolIdx = checked ((byte)i); KnownPools[i] = this; break; } } if (PoolIdx == 0) { ThrowHelper.ThrowInvalidOperationException("KnownPools slots exhausted. 64 pools ought to be enough for anybody."); } } IsRentAlwaysClean = rentAlwaysClean; Factory = (length) => { var memory = factory(this, length); if (IsRentAlwaysClean) { memory.GetSpan().Clear(); } AtomicCounter.Dispose(ref memory.CounterRef); ThrowHelper.DebugAssert(memory.IsPooled); return(memory); }; if (minLength <= 16) { minLength = 16; } _minBufferLengthPow2 = 32 - BitUtil.NumberOfLeadingZeros(minLength - 1); MinBufferLength = 1 << _minBufferLengthPow2; if (maxBucketsToTry < 0) { maxBucketsToTry = 0; } MaxBucketsToTry = maxBucketsToTry; if (maxLength <= 0) { throw new ArgumentOutOfRangeException(nameof(maxLength)); } if (maxBuffersPerBucketPerCore < 0) { throw new ArgumentOutOfRangeException(nameof(maxBuffersPerBucketPerCore)); } // Our bucketing algorithm has a min length of 2^4 and a max length of 2^30. // Constrain the actual max used to those values. const int maximumBufferLength = 0x40000000; if (maxLength > maximumBufferLength) { maxLength = maximumBufferLength; } else if (maxLength < minLength) { maxLength = minLength; } MaxBufferLength = maxLength; // Create the buckets. int maxBuckets = SelectBucketIndex(maxLength); var buckets = new MemoryBucket[maxBuckets + 1]; for (int i = 0; i < buckets.Length; i++) { buckets[i] = new MemoryBucket(this, GetMaxSizeForBucket(i), maxBuffersPerBucketPerCore); } _buckets = buckets; }