diff --git a/src/ImageSharp/Memory/Allocators/MemoryAllocator.cs b/src/ImageSharp/Memory/Allocators/MemoryAllocator.cs
index d6badf9282..8eaf0b6d69 100644
--- a/src/ImageSharp/Memory/Allocators/MemoryAllocator.cs
+++ b/src/ImageSharp/Memory/Allocators/MemoryAllocator.cs
@@ -12,8 +12,6 @@ namespace SixLabors.ImageSharp.Memory;
public abstract class MemoryAllocator
{
private const int OneGigabyte = 1 << 30;
- private long accumulativeAllocatedBytes;
- private int trackingSuppressionCount;
///
/// Gets the default platform-specific global instance that
@@ -25,44 +23,9 @@ public abstract class MemoryAllocator
///
public static MemoryAllocator Default { get; } = Create();
- ///
- /// Gets the maximum number of bytes that can be allocated by a memory group.
- ///
- ///
- /// The allocation limit is determined by the process architecture: 4 GB for 64-bit processes and
- /// 1 GB for 32-bit processes.
- ///
- internal long MemoryGroupAllocationLimitBytes { get; private protected set; } = Environment.Is64BitProcess ? 4L * OneGigabyte : OneGigabyte;
-
- ///
- /// Gets the maximum allowed total allocation size, in bytes, for the current process.
- ///
- ///
- /// Defaults to , effectively imposing no limit on total allocations.
- /// This property can be set to enforce a cap on total memory usage across all allocations made through this allocator instance, providing
- /// a safeguard against excessive memory consumption.
- /// When the cumulative size of active allocations exceeds this limit, an will be thrown to
- /// prevent further allocations and signal that the limit has been breached.
- ///
- internal long AccumulativeAllocationLimitBytes { get; private protected set; } = long.MaxValue;
+ internal long MemoryGroupAllocationLimitBytes { get; private set; } = Environment.Is64BitProcess ? 4L * OneGigabyte : OneGigabyte;
- ///
- /// Gets the maximum size, in bytes, that can be allocated for a single buffer.
- ///
- ///
- /// The single buffer allocation limit is set to 1 GB by default.
- ///
- internal int SingleBufferAllocationLimitBytes { get; private protected set; } = OneGigabyte;
-
- ///
- /// Gets a value indicating whether change tracking is currently suppressed for this instance.
- ///
- ///
- /// When change tracking is suppressed, modifications to the object will not be recorded or
- /// trigger change notifications. This property is used internally to temporarily disable tracking during
- /// batch updates or initialization.
- ///
- private bool IsTrackingSuppressed => Volatile.Read(ref this.trackingSuppressionCount) > 0;
+ internal int SingleBufferAllocationLimitBytes { get; private set; } = OneGigabyte;
///
/// Gets the length of the largest contiguous buffer that can be handled by this allocator instance in bytes.
@@ -90,11 +53,6 @@ public static MemoryAllocator Create(MemoryAllocatorOptions options)
allocator.SingleBufferAllocationLimitBytes = (int)Math.Min(allocator.SingleBufferAllocationLimitBytes, allocator.MemoryGroupAllocationLimitBytes);
}
- if (options.AccumulativeAllocationLimitMegabytes.HasValue)
- {
- allocator.AccumulativeAllocationLimitBytes = options.AccumulativeAllocationLimitMegabytes.Value * 1024L * 1024L;
- }
-
return allocator;
}
@@ -114,10 +72,6 @@ public abstract IMemoryOwner Allocate(int length, AllocationOptions option
/// Releases all retained resources not being in use.
/// Eg: by resetting array pools and letting GC to free the arrays.
///
- ///
- /// This does not dispose active allocations; callers are responsible for disposing all
- /// instances to release memory.
- ///
public virtual void ReleaseRetainedResources()
{
}
@@ -148,137 +102,11 @@ internal MemoryGroup AllocateGroup(
InvalidMemoryOperationException.ThrowAllocationOverLimitException(totalLengthInBytes, this.MemoryGroupAllocationLimitBytes);
}
- long totalLengthInBytesLong = (long)totalLengthInBytes;
- this.ReserveAllocation(totalLengthInBytesLong);
-
- using (this.SuppressTracking())
- {
- try
- {
- MemoryGroup group = this.AllocateGroupCore(totalLength, totalLengthInBytesLong, bufferAlignment, options);
- group.SetAllocationTracking(this, totalLengthInBytesLong);
- return group;
- }
- catch
- {
- this.ReleaseAccumulatedBytes(totalLengthInBytesLong);
- throw;
- }
- }
+ // Cast to long is safe because we already checked that the total length is within the limit.
+ return this.AllocateGroupCore(totalLength, (long)totalLengthInBytes, bufferAlignment, options);
}
internal virtual MemoryGroup AllocateGroupCore(long totalLengthInElements, long totalLengthInBytes, int bufferAlignment, AllocationOptions options)
where T : struct
=> MemoryGroup.Allocate(this, totalLengthInElements, bufferAlignment, options);
-
- ///
- /// Tracks the allocation of an instance after reserving bytes.
- ///
- /// Type of the data stored in the buffer.
- /// The allocation to track.
- /// The allocation size in bytes.
- /// The tracked allocation.
- protected IMemoryOwner TrackAllocation(IMemoryOwner owner, ulong lengthInBytes)
- where T : struct
- {
- if (this.IsTrackingSuppressed || lengthInBytes == 0)
- {
- return owner;
- }
-
- return new TrackingMemoryOwner(owner, this, (long)lengthInBytes);
- }
-
- ///
- /// Reserves accumulative allocation bytes before creating the underlying buffer.
- ///
- /// The number of bytes to reserve.
- protected void ReserveAllocation(long lengthInBytes)
- {
- if (this.IsTrackingSuppressed || lengthInBytes <= 0)
- {
- return;
- }
-
- long total = Interlocked.Add(ref this.accumulativeAllocatedBytes, lengthInBytes);
- if (total > this.AccumulativeAllocationLimitBytes)
- {
- _ = Interlocked.Add(ref this.accumulativeAllocatedBytes, -lengthInBytes);
- InvalidMemoryOperationException.ThrowAllocationOverLimitException((ulong)lengthInBytes, this.AccumulativeAllocationLimitBytes);
- }
- }
-
- ///
- /// Releases accumulative allocation bytes previously tracked by this allocator.
- ///
- /// The number of bytes to release.
- internal void ReleaseAccumulatedBytes(long lengthInBytes)
- {
- if (lengthInBytes <= 0)
- {
- return;
- }
-
- _ = Interlocked.Add(ref this.accumulativeAllocatedBytes, -lengthInBytes);
- }
-
- ///
- /// Suppresses accumulative allocation tracking for the lifetime of the returned scope.
- ///
- /// An that restores tracking when disposed.
- internal IDisposable SuppressTracking() => new TrackingSuppressionScope(this);
-
- ///
- /// Temporarily suppresses accumulative allocation tracking within a scope.
- ///
- private sealed class TrackingSuppressionScope : IDisposable
- {
- private MemoryAllocator? allocator;
-
- public TrackingSuppressionScope(MemoryAllocator allocator)
- {
- this.allocator = allocator;
- _ = Interlocked.Increment(ref allocator.trackingSuppressionCount);
- }
-
- public void Dispose()
- {
- if (this.allocator != null)
- {
- _ = Interlocked.Decrement(ref this.allocator.trackingSuppressionCount);
- this.allocator = null;
- }
- }
- }
-
- ///
- /// Wraps an to release accumulative tracking on dispose.
- ///
- private sealed class TrackingMemoryOwner : IMemoryOwner
- where T : struct
- {
- private IMemoryOwner? owner;
- private readonly MemoryAllocator allocator;
- private readonly long lengthInBytes;
-
- public TrackingMemoryOwner(IMemoryOwner owner, MemoryAllocator allocator, long lengthInBytes)
- {
- this.owner = owner;
- this.allocator = allocator;
- this.lengthInBytes = lengthInBytes;
- }
-
- public Memory Memory => this.owner?.Memory ?? Memory.Empty;
-
- public void Dispose()
- {
- // Ensure only one caller disposes the inner owner and releases the reservation.
- IMemoryOwner? inner = Interlocked.Exchange(ref this.owner, null);
- if (inner != null)
- {
- inner.Dispose();
- this.allocator.ReleaseAccumulatedBytes(this.lengthInBytes);
- }
- }
- }
}
diff --git a/src/ImageSharp/Memory/Allocators/MemoryAllocatorOptions.cs b/src/ImageSharp/Memory/Allocators/MemoryAllocatorOptions.cs
index 3339203dac..d9ba62c1ef 100644
--- a/src/ImageSharp/Memory/Allocators/MemoryAllocatorOptions.cs
+++ b/src/ImageSharp/Memory/Allocators/MemoryAllocatorOptions.cs
@@ -10,7 +10,6 @@ public struct MemoryAllocatorOptions
{
private int? maximumPoolSizeMegabytes;
private int? allocationLimitMegabytes;
- private int? accumulativeAllocationLimitMegabytes;
///
/// Gets or sets a value defining the maximum size of the 's internal memory pool
@@ -18,7 +17,7 @@ public struct MemoryAllocatorOptions
///
public int? MaximumPoolSizeMegabytes
{
- readonly get => this.maximumPoolSizeMegabytes;
+ get => this.maximumPoolSizeMegabytes;
set
{
if (value.HasValue)
@@ -36,7 +35,7 @@ public int? MaximumPoolSizeMegabytes
///
public int? AllocationLimitMegabytes
{
- readonly get => this.allocationLimitMegabytes;
+ get => this.allocationLimitMegabytes;
set
{
if (value.HasValue)
@@ -47,29 +46,4 @@ public int? AllocationLimitMegabytes
this.allocationLimitMegabytes = value;
}
}
-
- ///
- /// Gets or sets a value defining the maximum total size that can be allocated by the allocator in Megabytes.
- /// means platform default: 2GB on 32-bit processes, 8GB on 64-bit processes.
- ///
- public int? AccumulativeAllocationLimitMegabytes
- {
- readonly get => this.accumulativeAllocationLimitMegabytes;
- set
- {
- if (value.HasValue)
- {
- Guard.MustBeGreaterThan(value.Value, 0, nameof(this.AccumulativeAllocationLimitMegabytes));
- if (this.AllocationLimitMegabytes.HasValue)
- {
- Guard.MustBeGreaterThanOrEqualTo(
- value.Value,
- this.AllocationLimitMegabytes.Value,
- nameof(this.AccumulativeAllocationLimitMegabytes));
- }
- }
-
- this.accumulativeAllocationLimitMegabytes = value;
- }
- }
}
diff --git a/src/ImageSharp/Memory/Allocators/SimpleGcMemoryAllocator.cs b/src/ImageSharp/Memory/Allocators/SimpleGcMemoryAllocator.cs
index 9cbb15713a..675afe8b9f 100644
--- a/src/ImageSharp/Memory/Allocators/SimpleGcMemoryAllocator.cs
+++ b/src/ImageSharp/Memory/Allocators/SimpleGcMemoryAllocator.cs
@@ -12,32 +12,6 @@ namespace SixLabors.ImageSharp.Memory;
///
public sealed class SimpleGcMemoryAllocator : MemoryAllocator
{
- ///
- /// Initializes a new instance of the class with default limits.
- ///
- public SimpleGcMemoryAllocator()
- : this(default)
- {
- }
-
- ///
- /// Initializes a new instance of the class with custom limits.
- ///
- /// The to apply.
- public SimpleGcMemoryAllocator(MemoryAllocatorOptions options)
- {
- if (options.AllocationLimitMegabytes.HasValue)
- {
- this.MemoryGroupAllocationLimitBytes = options.AllocationLimitMegabytes.Value * 1024L * 1024L;
- this.SingleBufferAllocationLimitBytes = (int)Math.Min(this.SingleBufferAllocationLimitBytes, this.MemoryGroupAllocationLimitBytes);
- }
-
- if (options.AccumulativeAllocationLimitMegabytes.HasValue)
- {
- this.AccumulativeAllocationLimitBytes = options.AccumulativeAllocationLimitMegabytes.Value * 1024L * 1024L;
- }
- }
-
///
protected internal override int GetBufferCapacityInBytes() => int.MaxValue;
@@ -55,18 +29,6 @@ public override IMemoryOwner Allocate(int length, AllocationOptions option
InvalidMemoryOperationException.ThrowAllocationOverLimitException(lengthInBytes, this.SingleBufferAllocationLimitBytes);
}
- long lengthInBytesLong = (long)lengthInBytes;
- this.ReserveAllocation(lengthInBytesLong);
-
- try
- {
- IMemoryOwner buffer = new BasicArrayBuffer(new T[length]);
- return this.TrackAllocation(buffer, lengthInBytes);
- }
- catch
- {
- this.ReleaseAccumulatedBytes(lengthInBytesLong);
- throw;
- }
+ return new BasicArrayBuffer(new T[length]);
}
}
diff --git a/src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs b/src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs
index e34860b37b..d5cd329f1b 100644
--- a/src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs
+++ b/src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs
@@ -92,24 +92,13 @@ public override IMemoryOwner Allocate(
if (lengthInBytes <= (ulong)this.sharedArrayPoolThresholdInBytes)
{
- long lengthInBytesLong = (long)lengthInBytes;
- this.ReserveAllocation(lengthInBytesLong);
-
- try
- {
- SharedArrayPoolBuffer buffer = new(length);
- if (options.Has(AllocationOptions.Clean))
- {
- buffer.GetSpan().Clear();
- }
-
- return this.TrackAllocation(buffer, lengthInBytes);
- }
- catch
+ SharedArrayPoolBuffer buffer = new(length);
+ if (options.Has(AllocationOptions.Clean))
{
- this.ReleaseAccumulatedBytes(lengthInBytesLong);
- throw;
+ buffer.GetSpan().Clear();
}
+
+ return buffer;
}
if (lengthInBytes <= (ulong)this.poolBufferSizeInBytes)
@@ -117,38 +106,12 @@ public override IMemoryOwner Allocate(
UnmanagedMemoryHandle mem = this.pool.Rent();
if (mem.IsValid)
{
- long lengthInBytesLong = (long)lengthInBytes;
- this.ReserveAllocation(lengthInBytesLong);
-
- try
- {
- UnmanagedBuffer buffer = this.pool.CreateGuardedBuffer(mem, length, options.Has(AllocationOptions.Clean));
- return this.TrackAllocation(buffer, lengthInBytes);
- }
- catch
- {
- this.ReleaseAccumulatedBytes(lengthInBytesLong);
- throw;
- }
+ UnmanagedBuffer buffer = this.pool.CreateGuardedBuffer(mem, length, options.Has(AllocationOptions.Clean));
+ return buffer;
}
}
- long nonPooledLengthInBytesLong = (long)lengthInBytes;
- this.ReserveAllocation(nonPooledLengthInBytesLong);
-
- try
- {
- using (this.nonPoolAllocator.SuppressTracking())
- {
- IMemoryOwner nonPooled = this.nonPoolAllocator.Allocate(length, options);
- return this.TrackAllocation(nonPooled, lengthInBytes);
- }
- }
- catch
- {
- this.ReleaseAccumulatedBytes(nonPooledLengthInBytesLong);
- throw;
- }
+ return this.nonPoolAllocator.Allocate(length, options);
}
///
@@ -181,10 +144,7 @@ internal override MemoryGroup AllocateGroupCore(
return poolGroup;
}
- using (this.nonPoolAllocator.SuppressTracking())
- {
- return MemoryGroup.Allocate(this.nonPoolAllocator, totalLengthInElements, bufferAlignment, options);
- }
+ return MemoryGroup.Allocate(this.nonPoolAllocator, totalLengthInElements, bufferAlignment, options);
}
public override void ReleaseRetainedResources() => this.pool.Release();
diff --git a/src/ImageSharp/Memory/Allocators/UnmanagedMemoryAllocator.cs b/src/ImageSharp/Memory/Allocators/UnmanagedMemoryAllocator.cs
index 73cef8b5ee..daf1a79925 100644
--- a/src/ImageSharp/Memory/Allocators/UnmanagedMemoryAllocator.cs
+++ b/src/ImageSharp/Memory/Allocators/UnmanagedMemoryAllocator.cs
@@ -2,7 +2,6 @@
// Licensed under the Six Labors Split License.
using System.Buffers;
-using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory.Internals;
namespace SixLabors.ImageSharp.Memory;
@@ -20,26 +19,13 @@ internal class UnmanagedMemoryAllocator : MemoryAllocator
protected internal override int GetBufferCapacityInBytes() => this.bufferCapacityInBytes;
public override IMemoryOwner Allocate(int length, AllocationOptions options = AllocationOptions.None)
- where T : struct
{
- ulong lengthInBytes = (ulong)length * (ulong)Unsafe.SizeOf();
- long lengthInBytesLong = (long)lengthInBytes;
- this.ReserveAllocation(lengthInBytesLong);
-
- try
+ UnmanagedBuffer buffer = UnmanagedBuffer.Allocate(length);
+ if (options.Has(AllocationOptions.Clean))
{
- UnmanagedBuffer buffer = UnmanagedBuffer.Allocate(length);
- if (options.Has(AllocationOptions.Clean))
- {
- buffer.GetSpan().Clear();
- }
-
- return this.TrackAllocation(buffer, lengthInBytes);
- }
- catch
- {
- this.ReleaseAccumulatedBytes(lengthInBytesLong);
- throw;
+ buffer.GetSpan().Clear();
}
+
+ return buffer;
}
}
diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/IMemoryGroup{T}.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/IMemoryGroup{T}.cs
index 03f26aab04..7e9719ea75 100644
--- a/src/ImageSharp/Memory/DiscontiguousBuffers/IMemoryGroup{T}.cs
+++ b/src/ImageSharp/Memory/DiscontiguousBuffers/IMemoryGroup{T}.cs
@@ -15,12 +15,12 @@ public interface IMemoryGroup : IReadOnlyList>
/// Gets the number of elements per contiguous sub-buffer preceding the last buffer.
/// The last buffer is allowed to be smaller.
///
- public int BufferLength { get; }
+ int BufferLength { get; }
///
/// Gets the aggregate number of elements in the group.
///
- public long TotalLength { get; }
+ long TotalLength { get; }
///
/// Gets a value indicating whether the group has been invalidated.
@@ -29,7 +29,7 @@ public interface IMemoryGroup : IReadOnlyList>
/// Invalidation usually occurs when an image processor capable to alter the image dimensions replaces
/// the image buffers internally.
///
- public bool IsValid { get; }
+ bool IsValid { get; }
///
/// Returns a value-type implementing an allocation-free enumerator of the memory groups in the current
@@ -39,5 +39,5 @@ public interface IMemoryGroup : IReadOnlyList>
/// implementation, which is still available when casting to one of the underlying interfaces.
///
/// A new instance mapping the current values in use.
- public new MemoryGroupEnumerator GetEnumerator();
+ new MemoryGroupEnumerator GetEnumerator();
}
diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs
index 75e93ce7f8..950e2a019e 100644
--- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs
+++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Consumed.cs
@@ -31,23 +31,23 @@ public override int Count
///
[MethodImpl(InliningOptions.ShortMethod)]
- public override MemoryGroupEnumerator GetEnumerator() => new(this);
+ public override MemoryGroupEnumerator GetEnumerator()
+ {
+ return new MemoryGroupEnumerator(this);
+ }
///
IEnumerator> IEnumerable>.GetEnumerator()
-
+ {
/* The runtime sees the Array class as if it implemented the
* type-generic collection interfaces explicitly, so here we
* can just cast the source array to IList> (or to
* an equivalent type), and invoke the generic GetEnumerator
* method directly from that interface reference. This saves
* having to create our own iterator block here. */
- => ((IList>)this.source).GetEnumerator();
-
- public override void Dispose()
- {
- this.View.Invalidate();
- this.ReleaseAllocationTracking();
+ return ((IList>)this.source).GetEnumerator();
}
+
+ public override void Dispose() => this.View.Invalidate();
}
}
diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs
index be92272bbe..af896ee0e1 100644
--- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs
+++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs
@@ -73,8 +73,8 @@ private static IMemoryOwner[] CreateBuffers(
result[i] = currentBuffer;
}
- ObservedBuffer lastBuffer = ObservedBuffer.Create(pooledBuffers[^1], sizeOfLastBuffer, options);
- result[^1] = lastBuffer;
+ ObservedBuffer lastBuffer = ObservedBuffer.Create(pooledBuffers[pooledBuffers.Length - 1], sizeOfLastBuffer, options);
+ result[result.Length - 1] = lastBuffer;
return result;
}
@@ -155,7 +155,6 @@ public override void Dispose()
}
}
- this.ReleaseAllocationTracking();
this.memoryOwners = null;
this.IsValid = false;
this.groupLifetimeGuard = null;
diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs
index aa0e188959..6dd99fcb02 100644
--- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs
+++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs
@@ -22,9 +22,6 @@ internal abstract partial class MemoryGroup : IMemoryGroup, IDisposable
private static readonly int ElementSize = Unsafe.SizeOf();
private MemoryGroupSpanCache memoryGroupSpanCache;
- private MemoryAllocator? trackingAllocator;
- private long trackingLengthInBytes;
- private int trackingReleased;
private MemoryGroup(int bufferLength, long totalLength)
{
@@ -55,45 +52,16 @@ private MemoryGroup(int bufferLength, long totalLength)
///
public abstract MemoryGroupEnumerator GetEnumerator();
- ///
- /// Configures allocation tracking by specifying the allocator and the length, in bytes, to be tracked.
- ///
- /// The memory allocator to use for tracking allocations.
- /// The length, in bytes, of the memory region to track. Must be greater than or equal to zero.
- ///
- /// Intended for initialization; callers should avoid changing tracking state concurrently with disposal.
- ///
- internal void SetAllocationTracking(MemoryAllocator allocator, long lengthInBytes)
- {
- this.trackingAllocator = allocator;
- this.trackingLengthInBytes = lengthInBytes;
- }
-
- ///
- /// Releases any resources or tracking information associated with allocation tracking for this instance.
- ///
- ///
- /// This method is intended to be called when allocation tracking is no longer needed. It is safe
- /// to call multiple times; subsequent calls after the first have no effect, even when called concurrently.
- ///
- internal void ReleaseAllocationTracking()
- {
- if (Interlocked.Exchange(ref this.trackingReleased, 1) == 0 && this.trackingAllocator != null)
- {
- this.trackingAllocator.ReleaseAccumulatedBytes(this.trackingLengthInBytes);
- this.trackingAllocator = null;
- }
- }
-
///
IEnumerator> IEnumerable>.GetEnumerator()
-
+ {
/* This method is implemented in each derived class.
* Implementing the method here as non-abstract and throwing,
* then reimplementing it explicitly in each derived class, is
* a workaround for the lack of support for abstract explicit
* interface method implementations in C#. */
- => throw new NotImplementedException($"The type {this.GetType()} needs to override IEnumerable>.GetEnumerator()");
+ throw new NotImplementedException($"The type {this.GetType()} needs to override IEnumerable>.GetEnumerator()");
+ }
///
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable>)this).GetEnumerator();
diff --git a/tests/ImageSharp.Tests/Memory/Allocators/SimpleGcMemoryAllocatorTests.cs b/tests/ImageSharp.Tests/Memory/Allocators/SimpleGcMemoryAllocatorTests.cs
index c33e6d1070..0e791c5d97 100644
--- a/tests/ImageSharp.Tests/Memory/Allocators/SimpleGcMemoryAllocatorTests.cs
+++ b/tests/ImageSharp.Tests/Memory/Allocators/SimpleGcMemoryAllocatorTests.cs
@@ -48,50 +48,6 @@ public unsafe void Allocate_MemoryIsPinnableMultipleTimes()
}
}
- [Fact]
- public void Allocate_AccumulativeLimit_ReleasesOnOwnerDispose()
- {
- SimpleGcMemoryAllocator allocator = new(new MemoryAllocatorOptions
- {
- AccumulativeAllocationLimitMegabytes = 1
- });
- const int oneMb = 1 << 20;
-
- // Reserve the full limit with a single owner.
- IMemoryOwner b0 = allocator.Allocate(oneMb);
-
- // Additional allocation should exceed the limit while the owner is live.
- Assert.Throws(() => allocator.Allocate(1));
-
- // Disposing the owner releases the reservation.
- b0.Dispose();
-
- // Allocation should succeed after the reservation is released.
- allocator.Allocate(oneMb).Dispose();
- }
-
- [Fact]
- public void AllocateGroup_AccumulativeLimit_ReleasesOnGroupDispose()
- {
- SimpleGcMemoryAllocator allocator = new(new MemoryAllocatorOptions
- {
- AccumulativeAllocationLimitMegabytes = 1
- });
- const int oneMb = 1 << 20;
-
- // Reserve the full limit with a single group.
- MemoryGroup g0 = allocator.AllocateGroup(oneMb, 1024);
-
- // Additional allocation should exceed the limit while the group is live.
- Assert.Throws(() => allocator.AllocateGroup(1, 1024));
-
- // Disposing the group releases the reservation.
- g0.Dispose();
-
- // Allocation should succeed after the reservation is released.
- allocator.AllocateGroup(oneMb, 1024).Dispose();
- }
-
[StructLayout(LayoutKind.Explicit, Size = 512)]
private struct BigStruct
{
diff --git a/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs b/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs
index 06da3505e1..1d185a0de9 100644
--- a/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs
+++ b/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs
@@ -16,8 +16,8 @@ public class UniformUnmanagedPoolMemoryAllocatorTests
{
public class BufferTests1 : BufferTestSuite
{
- private static UniformUnmanagedMemoryPoolMemoryAllocator CreateMemoryAllocator() =>
- new(
+ private static MemoryAllocator CreateMemoryAllocator() =>
+ new UniformUnmanagedMemoryPoolMemoryAllocator(
sharedArrayPoolThresholdInBytes: 1024,
poolBufferSizeInBytes: 2048,
maxPoolSizeInBytes: 2048 * 4,
@@ -31,8 +31,8 @@ public BufferTests1()
public class BufferTests2 : BufferTestSuite
{
- private static UniformUnmanagedMemoryPoolMemoryAllocator CreateMemoryAllocator() =>
- new(
+ private static MemoryAllocator CreateMemoryAllocator() =>
+ new UniformUnmanagedMemoryPoolMemoryAllocator(
sharedArrayPoolThresholdInBytes: 512,
poolBufferSizeInBytes: 1024,
maxPoolSizeInBytes: 1024 * 4,
@@ -179,8 +179,8 @@ static void RunTest()
g1.Dispose();
// Do some unmanaged allocations to make sure new non-pooled unmanaged allocations will grab different memory:
- IntPtr dummy1 = Marshal.AllocHGlobal(checked((IntPtr)B(8)));
- IntPtr dummy2 = Marshal.AllocHGlobal(checked((IntPtr)B(8)));
+ IntPtr dummy1 = Marshal.AllocHGlobal((IntPtr)B(8));
+ IntPtr dummy2 = Marshal.AllocHGlobal((IntPtr)B(8));
using MemoryGroup g2 = allocator.AllocateGroup(B(8), 1024);
using MemoryGroup g3 = allocator.AllocateGroup(B(8), 1024);
@@ -433,50 +433,6 @@ public void AllocateGroup_OverLimit_ThrowsInvalidMemoryOperationException()
Assert.Throws(() => allocator.AllocateGroup(5 * oneMb, 1024));
}
- [Fact]
- public void Allocate_AccumulativeLimit_ReleasesOnOwnerDispose()
- {
- MemoryAllocator allocator = MemoryAllocator.Create(new MemoryAllocatorOptions
- {
- AccumulativeAllocationLimitMegabytes = 1
- });
- const int oneMb = 1 << 20;
-
- // Reserve the full limit with a single owner.
- IMemoryOwner b0 = allocator.Allocate(oneMb);
-
- // Additional allocation should exceed the limit while the owner is live.
- Assert.Throws(() => allocator.Allocate(1));
-
- // Disposing the owner releases the reservation.
- b0.Dispose();
-
- // Allocation should succeed after the reservation is released.
- allocator.Allocate(oneMb).Dispose();
- }
-
- [Fact]
- public void AllocateGroup_AccumulativeLimit_ReleasesOnGroupDispose()
- {
- MemoryAllocator allocator = MemoryAllocator.Create(new MemoryAllocatorOptions
- {
- AccumulativeAllocationLimitMegabytes = 1
- });
- const int oneMb = 1 << 20;
-
- // Reserve the full limit with a single group.
- MemoryGroup g0 = allocator.AllocateGroup(oneMb, 1024);
-
- // Additional allocation should exceed the limit while the group is live.
- Assert.Throws(() => allocator.AllocateGroup(1, 1024));
-
- // Disposing the group releases the reservation.
- g0.Dispose();
-
- // Allocation should succeed after the reservation is released.
- allocator.AllocateGroup(oneMb, 1024).Dispose();
- }
-
[ConditionalFact(typeof(Environment), nameof(Environment.Is64BitProcess))]
public void MemoryAllocator_Create_SetHighLimit()
{
diff --git a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.Allocate.cs b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.Allocate.cs
index cca2230e6f..678a089a85 100644
--- a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.Allocate.cs
+++ b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.Allocate.cs
@@ -98,15 +98,7 @@ public void Allocate_FromPool_BufferSizesAreCorrect(
[InlineData(AllocationOptions.Clean)]
public unsafe void Allocate_FromPool_AllocationOptionsAreApplied(AllocationOptions options)
{
- // Disable trimming to avoid buffers being freed between Return and TryAllocate by the
- // trim timer or the Gen2 GC callback.
- UniformUnmanagedMemoryPool pool = new(
- 10,
- 5,
- new UniformUnmanagedMemoryPool.TrimSettings
- {
- Rate = 0
- });
+ UniformUnmanagedMemoryPool pool = new(10, 5);
UnmanagedMemoryHandle[] buffers = pool.Rent(5);
foreach (UnmanagedMemoryHandle b in buffers)
{