public void Trim(uint tickCount, int id, Utilities.MemoryPressure pressure, int bucketSize)
 {
     LockedStack[] stacks = _perCoreStacks;
     for (int i = 0; i < stacks.Length; i++)
     {
         stacks[i].Trim(tickCount, id, pressure, bucketSize);
     }
 }
        public bool Trim()
        {
            int milliseconds = Environment.TickCount;

            Utilities.MemoryPressure pressure = Utilities.GetMemoryPressure();

            ArrayPoolEventSource log = ArrayPoolEventSource.Log;

            if (log.IsEnabled())
            {
                log.BufferTrimPoll(milliseconds, (int)pressure);
            }

            PerCoreLockedStacks?[] perCoreBuckets = _buckets;
            for (int i = 0; i < perCoreBuckets.Length; i++)
            {
                perCoreBuckets[i]?.Trim((uint)milliseconds, Id, pressure, Utilities.GetMaxSizeForBucket(i));
            }

            if (pressure == Utilities.MemoryPressure.High)
            {
                // Under high pressure, release all thread locals
                if (log.IsEnabled())
                {
                    foreach (KeyValuePair <T[]?[], object?> tlsBuckets in _allTlsBuckets)
                    {
                        T[]?[] buckets = tlsBuckets.Key;
                        for (int i = 0; i < buckets.Length; i++)
                        {
                            T[]? buffer = Interlocked.Exchange(ref buckets[i], null);
                            if (buffer is not null)
                            {
                                // As we don't want to take a perf hit in the rent path it
                                // is possible that a buffer could be rented as we "free" it.
                                log.BufferTrimmed(buffer.GetHashCode(), buffer.Length, Id);
                            }
                        }
                    }
                }
                else
                {
                    foreach (KeyValuePair <T[]?[], object?> tlsBuckets in _allTlsBuckets)
                    {
                        Array.Clear(tlsBuckets.Key);
                    }
                }
            }

            return(true);
        }
            public void Trim(uint tickCount, int id, Utilities.MemoryPressure pressure, int bucketSize)
            {
                const uint StackTrimAfterMS      = 60 * 1000;                     // Trim after 60 seconds for low/moderate pressure
                const uint StackHighTrimAfterMS  = 10 * 1000;                     // Trim after 10 seconds for high pressure
                const uint StackRefreshMS        = StackTrimAfterMS / 4;          // Time bump after trimming (1/4 trim time)
                const int  StackLowTrimCount     = 1;                             // Trim one item when pressure is low
                const int  StackMediumTrimCount  = 2;                             // Trim two items when pressure is moderate
                const int  StackHighTrimCount    = MaxBuffersPerArraySizePerCore; // Trim all items when pressure is high
                const int  StackLargeBucket      = 16384;                         // If the bucket is larger than this we'll trim an extra when under high pressure
                const int  StackModerateTypeSize = 16;                            // If T is larger than this we'll trim an extra when under high pressure
                const int  StackLargeTypeSize    = 32;                            // If T is larger than this we'll trim an extra (additional) when under high pressure

                if (_count == 0)
                {
                    return;
                }

                uint trimTicks = pressure == Utilities.MemoryPressure.High ? StackHighTrimAfterMS : StackTrimAfterMS;

                lock (this)
                {
                    if (_count > 0 && _firstStackItemMS > tickCount || (tickCount - _firstStackItemMS) > trimTicks)
                    {
                        // We've wrapped the tick count or elapsed enough time since the
                        // first item went into the stack. Drop the top item so it can
                        // be collected and make the stack look a little newer.

                        ArrayPoolEventSource log = ArrayPoolEventSource.Log;
                        int trimCount            = StackLowTrimCount;
                        switch (pressure)
                        {
                        case Utilities.MemoryPressure.High:
                            trimCount = StackHighTrimCount;

                            // When pressure is high, aggressively trim larger arrays.
                            if (bucketSize > StackLargeBucket)
                            {
                                trimCount++;
                            }
                            if (Unsafe.SizeOf <T>() > StackModerateTypeSize)
                            {
                                trimCount++;
                            }
                            if (Unsafe.SizeOf <T>() > StackLargeTypeSize)
                            {
                                trimCount++;
                            }
                            break;

                        case Utilities.MemoryPressure.Medium:
                            trimCount = StackMediumTrimCount;
                            break;
                        }

                        while (_count > 0 && trimCount-- > 0)
                        {
                            T[]? array = _arrays[--_count];
                            Debug.Assert(array is not null, "No nulls should have been present in slots < _count.");
                            _arrays[_count] = null;

                            if (log.IsEnabled())
                            {
                                log.BufferTrimmed(array.GetHashCode(), array.Length, id);
                            }
                        }

                        if (_count > 0 && _firstStackItemMS < uint.MaxValue - StackRefreshMS)
                        {
                            // Give the remaining items a bit more time
                            _firstStackItemMS += StackRefreshMS;
                        }
                    }
                }
            }