示例#1
0
 protected RetainableMemory(AtomicCounter counter)
 {
     if (counter.IsValid)
     {
         if (counter.Count != 0)
         {
             ThrowHelper.ThrowArgumentException("counter.Count != 0");
         }
     }
     Counter = counter;
 }
示例#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);
        }
示例#3
0
            internal void Return(RetainableMemory <T> memory)
            {
                // Check to see if the buffer is the correct size for this bucket
                if (memory.LengthPow2 != _bufferLength)
                {
                    ThrowNotFromPool <RetainableMemory <T> >();
                }

                // While holding the spin lock, if there's room available in the bucket,
                // put the buffer into the next available slot.  Otherwise, we just drop it.
                // The try/finally is necessary to properly handle thread aborts on platforms
                // which have them.
                int disposed = 0;

#if !NETCOREAPP
                try
#endif
                {
                    var spinner = new SpinWait();
                    while (0 != Interlocked.CompareExchange(ref _locker, 1, 0))
                    {
                        spinner.SpinOnce();
                    }

                    var pooled = _index != 0;

                    if (pooled)
                    {
                        if ((disposed = AtomicCounter.TryDispose(ref memory.CounterRef)) == 0)
                        {
                            _buffers[--_index] = memory;
                            Debug.Assert(AtomicCounter.GetIsDisposed(ref memory.CounterRef));
                            memory._isPooled = true;
                        }
                    }
                    else
                    {
                        memory.DisposeFinalize();
                    }
                }
#if !NETCOREAPP
                finally
#endif
                {
                    Volatile.Write(ref _locker, 0);
                }
                // after unlock
                if (disposed != 0)
                {
                    AtomicCounter.ThrowNonZeroTryDispose(disposed);
                }
            }
示例#4
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);
        }
示例#5
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;
        }