Beispiel #1
0
        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;
        }
Beispiel #2
0
        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);
        }
Beispiel #3
0
        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);
        }
Beispiel #4
0
        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;
        }