22// Licensed under the Six Labors Split License.
33
44using System . Buffers ;
5+ using System . Diagnostics . CodeAnalysis ;
6+ using System . Runtime . CompilerServices ;
57
68namespace SixLabors . ImageSharp . Memory ;
79
@@ -10,6 +12,8 @@ namespace SixLabors.ImageSharp.Memory;
1012/// </summary>
1113public abstract class MemoryAllocator
1214{
15+ private const int OneGigabyte = 1 << 30 ;
16+
1317 /// <summary>
1418 /// Gets the default platform-specific global <see cref="MemoryAllocator"/> instance that
1519 /// serves as the default value for <see cref="Configuration.MemoryAllocator"/>.
@@ -20,6 +24,12 @@ public abstract class MemoryAllocator
2024 /// </summary>
2125 public static MemoryAllocator Default { get ; } = Create ( ) ;
2226
27+ internal long MemoryGroupAllocationLimitBytes { get ; private set ; } = Environment . Is64BitProcess ?
28+ 4L * OneGigabyte :
29+ OneGigabyte ;
30+
31+ internal int SingleBufferAllocationLimitBytes { get ; private set ; } = OneGigabyte ;
32+
2333 /// <summary>
2434 /// Gets the length of the largest contiguous buffer that can be handled by this allocator instance in bytes.
2535 /// </summary>
@@ -30,16 +40,24 @@ public abstract class MemoryAllocator
3040 /// Creates a default instance of a <see cref="MemoryAllocator"/> optimized for the executing platform.
3141 /// </summary>
3242 /// <returns>The <see cref="MemoryAllocator"/>.</returns>
33- public static MemoryAllocator Create ( ) =>
34- new UniformUnmanagedMemoryPoolMemoryAllocator ( null ) ;
43+ public static MemoryAllocator Create ( ) => Create ( default ) ;
3544
3645 /// <summary>
3746 /// Creates the default <see cref="MemoryAllocator"/> using the provided options.
3847 /// </summary>
3948 /// <param name="options">The <see cref="MemoryAllocatorOptions"/>.</param>
4049 /// <returns>The <see cref="MemoryAllocator"/>.</returns>
41- public static MemoryAllocator Create ( MemoryAllocatorOptions options ) =>
42- new UniformUnmanagedMemoryPoolMemoryAllocator ( options . MaximumPoolSizeMegabytes ) ;
50+ public static MemoryAllocator Create ( MemoryAllocatorOptions options )
51+ {
52+ UniformUnmanagedMemoryPoolMemoryAllocator allocator = new ( options . MaximumPoolSizeMegabytes ) ;
53+ if ( options . AllocationLimitMegabytes . HasValue )
54+ {
55+ allocator . MemoryGroupAllocationLimitBytes = options . AllocationLimitMegabytes . Value * 1024 * 1024 ;
56+ allocator . SingleBufferAllocationLimitBytes = ( int ) Math . Min ( allocator . SingleBufferAllocationLimitBytes , allocator . MemoryGroupAllocationLimitBytes ) ;
57+ }
58+
59+ return allocator ;
60+ }
4361
4462 /// <summary>
4563 /// Allocates an <see cref="IMemoryOwner{T}" />, holding a <see cref="Memory{T}"/> of length <paramref name="length"/>.
@@ -69,10 +87,31 @@ public virtual void ReleaseRetainedResources()
6987 /// <param name="options">The <see cref="AllocationOptions"/>.</param>
7088 /// <returns>A new <see cref="MemoryGroup{T}"/>.</returns>
7189 /// <exception cref="InvalidMemoryOperationException">Thrown when 'blockAlignment' converted to bytes is greater than the buffer capacity of the allocator.</exception>
72- internal virtual MemoryGroup < T > AllocateGroup < T > (
90+ internal MemoryGroup < T > AllocateGroup < T > (
7391 long totalLength ,
7492 int bufferAlignment ,
7593 AllocationOptions options = AllocationOptions . None )
7694 where T : struct
77- => MemoryGroup < T > . Allocate ( this , totalLength , bufferAlignment , options ) ;
95+ {
96+ long totalLengthInBytes = totalLength * Unsafe . SizeOf < T > ( ) ;
97+ if ( totalLengthInBytes < 0 )
98+ {
99+ ThrowNotRepresentable ( ) ;
100+ }
101+
102+ if ( totalLengthInBytes > this . MemoryGroupAllocationLimitBytes )
103+ {
104+ InvalidMemoryOperationException . ThrowAllocationOverLimitException ( totalLengthInBytes , this . MemoryGroupAllocationLimitBytes ) ;
105+ }
106+
107+ return this . AllocateGroupCore < T > ( totalLengthInBytes , totalLength , bufferAlignment , options ) ;
108+
109+ [ DoesNotReturn ]
110+ static void ThrowNotRepresentable ( ) =>
111+ throw new InvalidMemoryOperationException ( "Attempted to allocate a MemoryGroup of a size that is not representable." ) ;
112+ }
113+
114+ internal virtual MemoryGroup < T > AllocateGroupCore < T > ( long totalLengthInElements , long totalLengthInBytes , int bufferAlignment , AllocationOptions options )
115+ where T : struct
116+ => MemoryGroup < T > . Allocate ( this , totalLengthInElements , bufferAlignment , options ) ;
78117}
0 commit comments