diff --git a/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.Buffer{T}.cs b/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.Buffer{T}.cs
deleted file mode 100644
index 5200a2793c..0000000000
--- a/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.Buffer{T}.cs
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-using System;
-using System.Buffers;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using SixLabors.ImageSharp.Memory.Internals;
-
-namespace SixLabors.ImageSharp.Memory
-{
- ///
- /// Contains .
- ///
- public partial class ArrayPoolMemoryAllocator
- {
- ///
- /// The buffer implementation of .
- ///
- private class Buffer : ManagedBufferBase
- where T : struct
- {
- ///
- /// The length of the buffer.
- ///
- private readonly int length;
-
- ///
- /// A weak reference to the source pool.
- ///
- ///
- /// By using a weak reference here, we are making sure that array pools and their retained arrays are always GC-ed
- /// after a call to , regardless of having buffer instances still being in use.
- ///
- private WeakReference> sourcePoolReference;
-
- public Buffer(byte[] data, int length, ArrayPool sourcePool)
- {
- this.Data = data;
- this.length = length;
- this.sourcePoolReference = new WeakReference>(sourcePool);
- }
-
- ///
- /// Gets the buffer as a byte array.
- ///
- protected byte[] Data { get; private set; }
-
- ///
- public override Span GetSpan()
- {
- if (this.Data is null)
- {
- ThrowObjectDisposedException();
- }
-#if SUPPORTS_CREATESPAN
- ref byte r0 = ref MemoryMarshal.GetReference(this.Data);
- return MemoryMarshal.CreateSpan(ref Unsafe.As(ref r0), this.length);
-#else
- return MemoryMarshal.Cast(this.Data.AsSpan()).Slice(0, this.length);
-#endif
-
- }
-
- ///
- protected override void Dispose(bool disposing)
- {
- if (!disposing || this.Data is null || this.sourcePoolReference is null)
- {
- return;
- }
-
- if (this.sourcePoolReference.TryGetTarget(out ArrayPool pool))
- {
- pool.Return(this.Data);
- }
-
- this.sourcePoolReference = null;
- this.Data = null;
- }
-
- protected override object GetPinnableObject() => this.Data;
-
- [MethodImpl(InliningOptions.ColdPath)]
- private static void ThrowObjectDisposedException()
- {
- throw new ObjectDisposedException("ArrayPoolMemoryAllocator.Buffer");
- }
- }
- }
-}
diff --git a/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.CommonFactoryMethods.cs b/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.CommonFactoryMethods.cs
deleted file mode 100644
index 8aa1b90634..0000000000
--- a/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.CommonFactoryMethods.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-namespace SixLabors.ImageSharp.Memory
-{
- ///
- /// Contains common factory methods and configuration constants.
- ///
- public partial class ArrayPoolMemoryAllocator
- {
- ///
- /// The default value for: maximum size of pooled arrays in bytes.
- /// Currently set to 24MB, which is equivalent to 8 megapixels of raw RGBA32 data.
- ///
- internal const int DefaultMaxPooledBufferSizeInBytes = 24 * 1024 * 1024;
-
- ///
- /// The value for: The threshold to pool arrays in which has less buckets for memory safety.
- ///
- private const int DefaultBufferSelectorThresholdInBytes = 8 * 1024 * 1024;
-
- ///
- /// The default bucket count for .
- ///
- private const int DefaultLargePoolBucketCount = 6;
-
- ///
- /// The default bucket count for .
- ///
- private const int DefaultNormalPoolBucketCount = 16;
-
- // TODO: This value should be determined by benchmarking
- private const int DefaultBufferCapacityInBytes = int.MaxValue / 4;
-
- ///
- /// This is the default. Should be good for most use cases.
- ///
- /// The memory manager.
- public static ArrayPoolMemoryAllocator CreateDefault()
- {
- return new ArrayPoolMemoryAllocator(
- DefaultMaxPooledBufferSizeInBytes,
- DefaultBufferSelectorThresholdInBytes,
- DefaultLargePoolBucketCount,
- DefaultNormalPoolBucketCount,
- DefaultBufferCapacityInBytes);
- }
-
- ///
- /// For environments with very limited memory capabilities, only small buffers like image rows are pooled.
- ///
- /// The memory manager.
- public static ArrayPoolMemoryAllocator CreateWithMinimalPooling()
- {
- return new ArrayPoolMemoryAllocator(64 * 1024, 32 * 1024, 8, 24);
- }
-
- ///
- /// For environments with limited memory capabilities, only small array requests are pooled, which can result in reduced throughput.
- ///
- /// The memory manager.
- public static ArrayPoolMemoryAllocator CreateWithModeratePooling()
- {
- return new ArrayPoolMemoryAllocator(1024 * 1024, 32 * 1024, 16, 24);
- }
-
- ///
- /// For environments where memory capabilities are not an issue, the maximum amount of array requests are pooled which results in optimal throughput.
- ///
- /// The memory manager.
- public static ArrayPoolMemoryAllocator CreateWithAggressivePooling()
- {
- return new ArrayPoolMemoryAllocator(128 * 1024 * 1024, 32 * 1024 * 1024, 16, 32);
- }
- }
-}
diff --git a/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.cs b/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.cs
deleted file mode 100644
index eb34b813fe..0000000000
--- a/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.cs
+++ /dev/null
@@ -1,166 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-using System;
-using System.Buffers;
-using System.Runtime.CompilerServices;
-
-namespace SixLabors.ImageSharp.Memory
-{
- ///
- /// Implements by allocating memory from .
- ///
- [Obsolete("ArrayPoolMemoryAllocator is obsolete. Use MemoryAllocator.CreateDefault() instead.")]
- public sealed partial class ArrayPoolMemoryAllocator : MemoryAllocator
- {
- private readonly int maxArraysPerBucketNormalPool;
-
- private readonly int maxArraysPerBucketLargePool;
-
- ///
- /// The for small-to-medium buffers which is not kept clean.
- ///
- private ArrayPool normalArrayPool;
-
- ///
- /// The for huge buffers, which is not kept clean.
- ///
- private ArrayPool largeArrayPool;
-
- ///
- /// Initializes a new instance of the class.
- ///
- public ArrayPoolMemoryAllocator()
- : this(DefaultMaxPooledBufferSizeInBytes, DefaultBufferSelectorThresholdInBytes)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The maximum size of pooled arrays. Arrays over the thershold are gonna be always allocated.
- public ArrayPoolMemoryAllocator(int maxPoolSizeInBytes)
- : this(maxPoolSizeInBytes, GetLargeBufferThresholdInBytes(maxPoolSizeInBytes))
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The maximum size of pooled arrays. Arrays over the thershold are gonna be always allocated.
- /// Arrays over this threshold will be pooled in which has less buckets for memory safety.
- public ArrayPoolMemoryAllocator(int maxPoolSizeInBytes, int poolSelectorThresholdInBytes)
- : this(maxPoolSizeInBytes, poolSelectorThresholdInBytes, DefaultLargePoolBucketCount, DefaultNormalPoolBucketCount)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The maximum size of pooled arrays. Arrays over the thershold are gonna be always allocated.
- /// The threshold to pool arrays in which has less buckets for memory safety.
- /// Max arrays per bucket for the large array pool.
- /// Max arrays per bucket for the normal array pool.
- public ArrayPoolMemoryAllocator(
- int maxPoolSizeInBytes,
- int poolSelectorThresholdInBytes,
- int maxArraysPerBucketLargePool,
- int maxArraysPerBucketNormalPool)
- : this(
- maxPoolSizeInBytes,
- poolSelectorThresholdInBytes,
- maxArraysPerBucketLargePool,
- maxArraysPerBucketNormalPool,
- DefaultBufferCapacityInBytes)
- {
- }
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The maximum size of pooled arrays. Arrays over the thershold are gonna be always allocated.
- /// The threshold to pool arrays in which has less buckets for memory safety.
- /// Max arrays per bucket for the large array pool.
- /// Max arrays per bucket for the normal array pool.
- /// The length of the largest contiguous buffer that can be handled by this allocator instance.
- public ArrayPoolMemoryAllocator(
- int maxPoolSizeInBytes,
- int poolSelectorThresholdInBytes,
- int maxArraysPerBucketLargePool,
- int maxArraysPerBucketNormalPool,
- int bufferCapacityInBytes)
- {
- Guard.MustBeGreaterThan(maxPoolSizeInBytes, 0, nameof(maxPoolSizeInBytes));
- Guard.MustBeLessThanOrEqualTo(poolSelectorThresholdInBytes, maxPoolSizeInBytes, nameof(poolSelectorThresholdInBytes));
-
- this.MaxPoolSizeInBytes = maxPoolSizeInBytes;
- this.PoolSelectorThresholdInBytes = poolSelectorThresholdInBytes;
- this.BufferCapacityInBytes = bufferCapacityInBytes;
- this.maxArraysPerBucketLargePool = maxArraysPerBucketLargePool;
- this.maxArraysPerBucketNormalPool = maxArraysPerBucketNormalPool;
-
- this.InitArrayPools();
- }
-
- ///
- /// Gets the maximum size of pooled arrays in bytes.
- ///
- public int MaxPoolSizeInBytes { get; }
-
- ///
- /// Gets the threshold to pool arrays in which has less buckets for memory safety.
- ///
- public int PoolSelectorThresholdInBytes { get; }
-
- ///
- /// Gets the length of the largest contiguous buffer that can be handled by this allocator instance.
- ///
- public int BufferCapacityInBytes { get; internal set; } // Setter is internal for easy configuration in tests
-
- ///
- public override void ReleaseRetainedResources()
- {
- this.InitArrayPools();
- }
-
- ///
- protected internal override int GetBufferCapacityInBytes() => this.BufferCapacityInBytes;
-
- ///
- public override IMemoryOwner Allocate(int length, AllocationOptions options = AllocationOptions.None)
- {
- Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length));
- int itemSizeBytes = Unsafe.SizeOf();
- int bufferSizeInBytes = length * itemSizeBytes;
-
- ArrayPool pool = this.GetArrayPool(bufferSizeInBytes);
- byte[] byteArray = pool.Rent(bufferSizeInBytes);
-
- var buffer = new Buffer(byteArray, length, pool);
- if (options.Has(AllocationOptions.Clean))
- {
- buffer.GetSpan().Clear();
- }
-
- return buffer;
- }
-
- private static int GetLargeBufferThresholdInBytes(int maxPoolSizeInBytes) => maxPoolSizeInBytes / 4;
-
- [MethodImpl(InliningOptions.ColdPath)]
- private static void ThrowInvalidAllocationException(int length, int max) =>
- throw new InvalidMemoryOperationException(
- $"Requested allocation: '{length}' elements of '{typeof(T).Name}' is over the capacity in bytes '{max}' of the MemoryAllocator.");
-
- private ArrayPool GetArrayPool(int bufferSizeInBytes)
- {
- return bufferSizeInBytes <= this.PoolSelectorThresholdInBytes ? this.normalArrayPool : this.largeArrayPool;
- }
-
- private void InitArrayPools()
- {
- this.largeArrayPool = ArrayPool.Create(this.MaxPoolSizeInBytes, this.maxArraysPerBucketLargePool);
- this.normalArrayPool = ArrayPool.Create(this.PoolSelectorThresholdInBytes, this.maxArraysPerBucketNormalPool);
- }
- }
-}
diff --git a/tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressBenchmarks.cs b/tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressBenchmarks.cs
index 9d6804e64b..b998863e87 100644
--- a/tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressBenchmarks.cs
+++ b/tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressBenchmarks.cs
@@ -17,11 +17,6 @@ namespace SixLabors.ImageSharp.Benchmarks.LoadResizeSave
// private const JpegKind Filter = JpegKind.Progressive;
private const JpegKind Filter = JpegKind.Any;
-#pragma warning disable CS0618 // 'ArrayPoolMemoryAllocator' is obsolete
- private ArrayPoolMemoryAllocator arrayPoolMemoryAllocator;
-#pragma warning restore CS0618
- private MemoryAllocator defaultMemoryAllocator;
-
[GlobalSetup]
public void Setup()
{
@@ -32,11 +27,6 @@ namespace SixLabors.ImageSharp.Benchmarks.LoadResizeSave
};
Console.WriteLine($"ImageCount: {this.runner.ImageCount} Filter: {Filter}");
this.runner.Init();
- this.defaultMemoryAllocator = Configuration.Default.MemoryAllocator;
-
-#pragma warning disable CS0618 // 'ArrayPoolMemoryAllocator' is obsolete
- this.arrayPoolMemoryAllocator = ArrayPoolMemoryAllocator.CreateDefault();
-#pragma warning restore CS0618
}
private void ForEachImage(Action action, int maxDegreeOfParallelism)
@@ -59,17 +49,8 @@ namespace SixLabors.ImageSharp.Benchmarks.LoadResizeSave
[Benchmark(Baseline = true)]
[ArgumentsSource(nameof(ParallelismValues))]
- public void ImageSharp_DefaultMemoryAllocator(int maxDegreeOfParallelism)
- {
- Configuration.Default.MemoryAllocator = this.defaultMemoryAllocator;
- this.ForEachImage(this.runner.ImageSharpResize, maxDegreeOfParallelism);
- }
-
- [Benchmark]
- [ArgumentsSource(nameof(ParallelismValues))]
- public void ImageSharp_ArrayPoolMemoryAllocator(int maxDegreeOfParallelism)
+ public void ImageSharp(int maxDegreeOfParallelism)
{
- Configuration.Default.MemoryAllocator = this.arrayPoolMemoryAllocator;
this.ForEachImage(this.runner.ImageSharpResize, maxDegreeOfParallelism);
}
diff --git a/tests/ImageSharp.Tests.ProfilingSandbox/LoadResizeSaveParallelMemoryStress.cs b/tests/ImageSharp.Tests.ProfilingSandbox/LoadResizeSaveParallelMemoryStress.cs
index 873845393d..acec87ca58 100644
--- a/tests/ImageSharp.Tests.ProfilingSandbox/LoadResizeSaveParallelMemoryStress.cs
+++ b/tests/ImageSharp.Tests.ProfilingSandbox/LoadResizeSaveParallelMemoryStress.cs
@@ -192,20 +192,11 @@ namespace SixLabors.ImageSharp.Tests.ProfilingSandbox
}
}
- private enum AllocatorKind
- {
- Classic,
- Unmanaged
- }
-
private class CommandLineOptions
{
[Option('i', "imagesharp", Required = false, Default = false, HelpText = "Test ImageSharp without benchmark switching")]
public bool ImageSharp { get; set; }
- [Option('a', "allocator", Required = false, Default = AllocatorKind.Unmanaged, HelpText = "Select allocator: Classic (ArrayPoolMemoryAllocator) or Unmanaged")]
- public AllocatorKind Allocator { get; set; }
-
[Option('m', "max-contiguous", Required = false, Default = 4, HelpText = "Maximum size of contiguous pool buffers in MegaBytes")]
public int MaxContiguousPoolBufferMegaBytes { get; set; } = 4;
@@ -253,40 +244,29 @@ namespace SixLabors.ImageSharp.Tests.ProfilingSandbox
}
public override string ToString() =>
- $"p({this.MaxDegreeOfParallelism})_i({this.ImageSharp})_a({this.Allocator})_m({this.MaxContiguousPoolBufferMegaBytes})_s({this.MaxPoolSizeMegaBytes})_u({this.MaxCapacityOfNonPoolBuffersMegaBytes})_r({this.RepeatCount})_g({this.FinalGcCount})_e({this.ReleaseRetainedResourcesAtEnd})";
+ $"p({this.MaxDegreeOfParallelism})_i({this.ImageSharp})_m({this.MaxContiguousPoolBufferMegaBytes})_s({this.MaxPoolSizeMegaBytes})_u({this.MaxCapacityOfNonPoolBuffersMegaBytes})_r({this.RepeatCount})_g({this.FinalGcCount})_e({this.ReleaseRetainedResourcesAtEnd})";
public MemoryAllocator CreateMemoryAllocator()
{
- switch (this.Allocator)
+ if (this.TrimTimeSeconds.HasValue)
{
- case AllocatorKind.Classic:
-#pragma warning disable CS0618 // 'ArrayPoolMemoryAllocator' is obsolete
- return ArrayPoolMemoryAllocator.CreateDefault();
-#pragma warning restore CS0618
- case AllocatorKind.Unmanaged:
- if (this.TrimTimeSeconds.HasValue)
+ return new UniformUnmanagedMemoryPoolMemoryAllocator(
+ 1024 * 1024,
+ (int)B(this.MaxContiguousPoolBufferMegaBytes),
+ B(this.MaxPoolSizeMegaBytes),
+ (int)B(this.MaxCapacityOfNonPoolBuffersMegaBytes),
+ new UniformUnmanagedMemoryPool.TrimSettings
{
- return new UniformUnmanagedMemoryPoolMemoryAllocator(
- 1024 * 1024,
- (int)B(this.MaxContiguousPoolBufferMegaBytes),
- B(this.MaxPoolSizeMegaBytes),
- (int)B(this.MaxCapacityOfNonPoolBuffersMegaBytes),
- new UniformUnmanagedMemoryPool.TrimSettings
- {
- TrimPeriodMilliseconds = this.TrimTimeSeconds.Value * 1000
- });
- }
- else
- {
- return new UniformUnmanagedMemoryPoolMemoryAllocator(
- 1024 * 1024,
- (int)B(this.MaxContiguousPoolBufferMegaBytes),
- B(this.MaxPoolSizeMegaBytes),
- (int)B(this.MaxCapacityOfNonPoolBuffersMegaBytes));
- }
-
- default:
- throw new ArgumentOutOfRangeException();
+ TrimPeriodMilliseconds = this.TrimTimeSeconds.Value * 1000
+ });
+ }
+ else
+ {
+ return new UniformUnmanagedMemoryPoolMemoryAllocator(
+ 1024 * 1024,
+ (int)B(this.MaxContiguousPoolBufferMegaBytes),
+ B(this.MaxPoolSizeMegaBytes),
+ (int)B(this.MaxCapacityOfNonPoolBuffersMegaBytes));
}
}