diff --git a/Directory.Build.props b/Directory.Build.props
index b3e18e5a5a..4a0fb856da 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -26,4 +26,7 @@
true
+
+ $(DefineConstants);NETCORE31COMPATIBLE
+
diff --git a/src/ImageSharp/Advanced/AotCompilerTools.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs
index be2e964fc0..74b8a85b0e 100644
--- a/src/ImageSharp/Advanced/AotCompilerTools.cs
+++ b/src/ImageSharp/Advanced/AotCompilerTools.cs
@@ -524,7 +524,7 @@ namespace SixLabors.ImageSharp.Advanced
private static void AotCompileMemoryManagers()
where TPixel : unmanaged, IPixel
{
- AotCompileMemoryManager();
+ AotCompileMemoryManager();
AotCompileMemoryManager();
}
diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs
index 49b7aa79b0..0ac4c29eae 100644
--- a/src/ImageSharp/Configuration.cs
+++ b/src/ImageSharp/Configuration.cs
@@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp
///
/// Gets or sets the that is currently in use.
///
- public MemoryAllocator MemoryAllocator { get; set; } = ArrayPoolMemoryAllocator.CreateDefault();
+ public MemoryAllocator MemoryAllocator { get; set; } = MemoryAllocator.CreateDefault();
///
/// Gets the maximum header size of all the formats.
diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj
index 7719b12420..9e80518921 100644
--- a/src/ImageSharp/ImageSharp.csproj
+++ b/src/ImageSharp/ImageSharp.csproj
@@ -13,8 +13,8 @@
Image Resize Crop Gif Jpg Jpeg Bitmap Png Tga NetCore
A new, fully featured, fully managed, cross-platform, 2D graphics API for .NET
Debug;Release;Debug-InnerLoop;Release-InnerLoop
+ $(DefineConstants);DEBUG
-
diff --git a/src/ImageSharp/Memory/Allocators/AllocationOptions.cs b/src/ImageSharp/Memory/Allocators/AllocationOptions.cs
index 3c865f3578..72c785532b 100644
--- a/src/ImageSharp/Memory/Allocators/AllocationOptions.cs
+++ b/src/ImageSharp/Memory/Allocators/AllocationOptions.cs
@@ -1,21 +1,30 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
+using System;
+
namespace SixLabors.ImageSharp.Memory
{
///
/// Options for allocating buffers.
///
+ [Flags]
public enum AllocationOptions
{
///
/// Indicates that the buffer should just be allocated.
///
- None,
+ None = 0,
///
/// Indicates that the allocated buffer should be cleaned following allocation.
///
- Clean
+ Clean = 1,
+
+ ///
+ /// Affects only group allocations.
+ /// Indicates that the requested or should be made of contiguous blocks up to .
+ ///
+ Contiguous = 2
}
}
diff --git a/src/ImageSharp/Memory/Allocators/AllocationOptionsExtensions.cs b/src/ImageSharp/Memory/Allocators/AllocationOptionsExtensions.cs
new file mode 100644
index 0000000000..d3e5bca6ee
--- /dev/null
+++ b/src/ImageSharp/Memory/Allocators/AllocationOptionsExtensions.cs
@@ -0,0 +1,10 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+namespace SixLabors.ImageSharp.Memory
+{
+ internal static class AllocationOptionsExtensions
+ {
+ public static bool Has(this AllocationOptions options, AllocationOptions flag) => (options & flag) == flag;
+ }
+}
diff --git a/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.Buffer{T}.cs b/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.Buffer{T}.cs
index 0c35c88286..5200a2793c 100644
--- a/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.Buffer{T}.cs
+++ b/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.Buffer{T}.cs
@@ -10,7 +10,7 @@ using SixLabors.ImageSharp.Memory.Internals;
namespace SixLabors.ImageSharp.Memory
{
///
- /// Contains and .
+ /// Contains .
///
public partial class ArrayPoolMemoryAllocator
{
@@ -87,19 +87,5 @@ namespace SixLabors.ImageSharp.Memory
throw new ObjectDisposedException("ArrayPoolMemoryAllocator.Buffer");
}
}
-
- ///
- /// The implementation of .
- ///
- private sealed class ManagedByteBuffer : Buffer, IManagedByteBuffer
- {
- public ManagedByteBuffer(byte[] data, int length, ArrayPool sourcePool)
- : base(data, length, sourcePool)
- {
- }
-
- ///
- public byte[] Array => this.Data;
- }
}
}
diff --git a/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.CommonFactoryMethods.cs b/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.CommonFactoryMethods.cs
index 8aa1b90634..4b06f537b9 100644
--- a/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.CommonFactoryMethods.cs
+++ b/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.CommonFactoryMethods.cs
@@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Memory
/// This is the default. Should be good for most use cases.
///
/// The memory manager.
- public static ArrayPoolMemoryAllocator CreateDefault()
+ public static new ArrayPoolMemoryAllocator CreateDefault()
{
return new ArrayPoolMemoryAllocator(
DefaultMaxPooledBufferSizeInBytes,
diff --git a/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.cs b/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.cs
index a79e042a32..eb34b813fe 100644
--- a/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.cs
+++ b/src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.cs
@@ -10,6 +10,7 @@ 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;
@@ -136,7 +137,7 @@ namespace SixLabors.ImageSharp.Memory
byte[] byteArray = pool.Rent(bufferSizeInBytes);
var buffer = new Buffer(byteArray, length, pool);
- if (options == AllocationOptions.Clean)
+ if (options.Has(AllocationOptions.Clean))
{
buffer.GetSpan().Clear();
}
@@ -144,27 +145,7 @@ namespace SixLabors.ImageSharp.Memory
return buffer;
}
- ///
- public override IManagedByteBuffer AllocateManagedByteBuffer(int length, AllocationOptions options = AllocationOptions.None)
- {
- Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length));
-
- ArrayPool pool = this.GetArrayPool(length);
- byte[] byteArray = pool.Rent(length);
-
- var buffer = new ManagedByteBuffer(byteArray, length, pool);
- if (options == AllocationOptions.Clean)
- {
- buffer.GetSpan().Clear();
- }
-
- return buffer;
- }
-
- private static int GetLargeBufferThresholdInBytes(int maxPoolSizeInBytes)
- {
- return maxPoolSizeInBytes / 4;
- }
+ private static int GetLargeBufferThresholdInBytes(int maxPoolSizeInBytes) => maxPoolSizeInBytes / 4;
[MethodImpl(InliningOptions.ColdPath)]
private static void ThrowInvalidAllocationException(int length, int max) =>
diff --git a/src/ImageSharp/Memory/Allocators/IManagedByteBuffer.cs b/src/ImageSharp/Memory/Allocators/IManagedByteBuffer.cs
deleted file mode 100644
index 8088a2c47c..0000000000
--- a/src/ImageSharp/Memory/Allocators/IManagedByteBuffer.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-using System.Buffers;
-
-namespace SixLabors.ImageSharp.Memory
-{
- ///
- /// Represents a byte buffer backed by a managed array. Useful for interop with classic .NET API-s.
- ///
- public interface IManagedByteBuffer : IMemoryOwner
- {
- ///
- /// Gets the managed array backing this buffer instance.
- ///
- byte[] Array { get; }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Memory/Allocators/Internals/BasicArrayBuffer.cs b/src/ImageSharp/Memory/Allocators/Internals/BasicArrayBuffer.cs
index 3a3c695b2c..7dbbabff3a 100644
--- a/src/ImageSharp/Memory/Allocators/Internals/BasicArrayBuffer.cs
+++ b/src/ImageSharp/Memory/Allocators/Internals/BasicArrayBuffer.cs
@@ -2,11 +2,12 @@
// Licensed under the Apache License, Version 2.0.
using System;
+using System.Buffers;
namespace SixLabors.ImageSharp.Memory.Internals
{
///
- /// Wraps an array as an instance.
+ /// Wraps an array as an instance.
///
///
internal class BasicArrayBuffer : ManagedBufferBase
@@ -57,4 +58,4 @@ namespace SixLabors.ImageSharp.Memory.Internals
return this.Array;
}
}
-}
\ No newline at end of file
+}
diff --git a/src/ImageSharp/Memory/Allocators/Internals/BasicByteBuffer.cs b/src/ImageSharp/Memory/Allocators/Internals/BasicByteBuffer.cs
deleted file mode 100644
index 499a9228c1..0000000000
--- a/src/ImageSharp/Memory/Allocators/Internals/BasicByteBuffer.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) Six Labors.
-// Licensed under the Apache License, Version 2.0.
-
-namespace SixLabors.ImageSharp.Memory.Internals
-{
- ///
- /// Provides an based on .
- ///
- internal sealed class BasicByteBuffer : BasicArrayBuffer, IManagedByteBuffer
- {
- ///
- /// Initializes a new instance of the class.
- ///
- /// The byte array.
- internal BasicByteBuffer(byte[] array)
- : base(array)
- {
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp/Memory/Allocators/Internals/Gen2GcCallback.cs b/src/ImageSharp/Memory/Allocators/Internals/Gen2GcCallback.cs
new file mode 100644
index 0000000000..3a0479359a
--- /dev/null
+++ b/src/ImageSharp/Memory/Allocators/Internals/Gen2GcCallback.cs
@@ -0,0 +1,115 @@
+// Copyright (c) Six Labors.
+// Licensed under the Apache License, Version 2.0.
+
+// Port of BCL internal utility:
+// https://github.com/dotnet/runtime/blob/57bfe474518ab5b7cfe6bf7424a79ce3af9d6657/src/libraries/System.Private.CoreLib/src/System/Gen2GcCallback.cs
+#if NETCORE31COMPATIBLE
+using System;
+using System.Runtime.ConstrainedExecution;
+using System.Runtime.InteropServices;
+
+namespace SixLabors.ImageSharp.Memory.Internals
+{
+ ///
+ /// Schedules a callback roughly every gen 2 GC (you may see a Gen 0 an Gen 1 but only once)
+ /// (We can fix this by capturing the Gen 2 count at startup and testing, but I mostly don't care)
+ ///
+ internal sealed class Gen2GcCallback : CriticalFinalizerObject
+ {
+ private readonly Func callback0;
+ private readonly Func