public bool Trim() { Debug.Assert(s_trimBuffers); Debug.Assert(s_allTlsBuckets != null); int milliseconds = Environment.TickCount; MemoryPressure pressure = GetMemoryPressure(); PerCoreLockedStacks?[] perCoreBuckets = _buckets; for (int i = 0; i < perCoreBuckets.Length; i++) { perCoreBuckets[i]?.Trim((uint)milliseconds, Id, pressure, _bucketArraySizes[i]); } if (pressure == MemoryPressure.High) { foreach (KeyValuePair <T[]?[], object?> tlsBuckets in s_allTlsBuckets) { T[]?[] buckets = tlsBuckets.Key; Array.Clear(buckets, 0, buckets.Length); } } return(true); }
public void Trim(uint tickCount, int id, 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(uint tickCount, int id, MemoryPressure pressure, int[] bucketSizes) { LockedStack[] stacks = _perCoreStacks; for (int i = 0; i < stacks.Length; i++) { stacks[i].Trim(tickCount, id, pressure, bucketSizes[i]); } return(true); }
public void Trim(long now, MemoryPressure pressure, int bucketSize) { if (_count == 0) { return; } // 10 seconds under high pressure, otherwise 60 seconds var threshold = pressure == MemoryPressure.High ? 10000 : 60000; if (_ticks == 0) { _ticks = now; return; } if (now - _ticks <= threshold) { return; } int trimCount = 1; switch (pressure) { case MemoryPressure.Medium: { trimCount = 2; break; } case MemoryPressure.High: { if (bucketSize > 16384) { trimCount++; } var size = Unsafe.SizeOf <T>(); if (size > 32) { trimCount += 2; } else if (size > 16) { trimCount++; } break; } } while (_count > 0 && trimCount-- > 0) { _arrays[--_count] = null; } }
public bool Trim() { Debug.Assert(s_trimBuffers); Debug.Assert(s_allTlsBuckets != null); int milliseconds = Environment.TickCount; MemoryPressure pressure = 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, _bucketArraySizes[i]); } if (pressure == MemoryPressure.High) { // Under high pressure, release all thread locals if (log.IsEnabled()) { foreach (KeyValuePair <T[]?[], object?> tlsBuckets in s_allTlsBuckets) { T[]?[] buckets = tlsBuckets.Key; for (int i = 0; i < buckets.Length; i++) { T[]? buffer = Interlocked.Exchange(ref buckets[i], null); if (buffer != 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 s_allTlsBuckets) { T[]?[] buckets = tlsBuckets.Key; Array.Clear(buckets, 0, buckets.Length); } } } return(true); }
public A(params int[] dimension) { this.Dimension = dimension; this.Stride = A.BuildStride(dimension); int length = dimension.Length > 0 ? this.Stride[0] * dimension[0] : 0; this.Buffer = new T[length]; this.count = length; this.memoryPressure = this.SizeInBytes; MemoryPressure.Add(this.memoryPressure); }
internal SafeMILHandleMemoryPressure(long gcPressure) { _gcPressure = gcPressure; _refCount = 0; if (_gcPressure > SMALL_BITMAP_MEM) { MemoryPressure.Add(_gcPressure); } else { GC.AddMemoryPressure(_gcPressure); } }
internal void Release() { if (Interlocked.Decrement(ref _refCount) == 0) { if (_gcPressure > SMALL_BITMAP_MEM) { MemoryPressure.Remove(_gcPressure); } else { GC.RemoveMemoryPressure(_gcPressure); } _gcPressure = 0; } }
public bool Trim() { int milliseconds = Environment.TickCount; MemoryPressure pressure = GetMemoryPressure(); ArrayPoolEventSource log = ArrayPoolEventSource.Log; if (log.IsEnabled()) { log.BufferTrimPoll(milliseconds, (int)pressure); } foreach (PerCoreLockedStacks bucket in _buckets) { bucket?.Trim((uint)milliseconds, Id, pressure, _bucketArraySizes); } if (pressure == MemoryPressure.High) { // Under high pressure, release all thread locals foreach (KeyValuePair <T[][], object> tlsBuckets in s_AllTlsBuckets) { T[][] buckets = tlsBuckets.Key; for (int i = 0; i < NumBuckets; i++) { T[] buffer = buckets[i]; buckets[i] = null; if (log.IsEnabled() && buffer != null) { log.BufferTrimmed(buffer.GetHashCode(), buffer.Length, Id); } } } } return(true); }
public static void Main(string[] args) { if (args.Length != 2) { Usage(); return; } long iterations = 0; if (!long.TryParse(args[0], out iterations)) { Usage(); return; } if (iterations == 0) { iterations = 200; } MemoryPressure mp = new MemoryPressure(iterations); switch (args[1].ToLower()) { case "add": mp.AddMemoryPressure(); break; case "remove": mp.RemoveMemoryPressure(); break; default: Usage(); return; } }
public void Trim(uint tickCount, int id, 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 == 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 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 MemoryPressure.Medium: trimCount = StackMediumTrimCount; break; } while (_count > 0 && trimCount-- > 0) { T[]? array = _arrays[--_count]; Debug.Assert(array != 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; } } } }