2
2
// Licensed under the Six Labors Split License.
3
3
4
4
using System . Buffers ;
5
+ using System . Diagnostics . CodeAnalysis ;
6
+ using System . Runtime . CompilerServices ;
5
7
6
8
namespace SixLabors . ImageSharp . Memory ;
7
9
@@ -10,6 +12,8 @@ namespace SixLabors.ImageSharp.Memory;
10
12
/// </summary>
11
13
public abstract class MemoryAllocator
12
14
{
15
+ private const int OneGigabyte = 1 << 30 ;
16
+
13
17
/// <summary>
14
18
/// Gets the default platform-specific global <see cref="MemoryAllocator"/> instance that
15
19
/// serves as the default value for <see cref="Configuration.MemoryAllocator"/>.
@@ -20,6 +24,12 @@ public abstract class MemoryAllocator
20
24
/// </summary>
21
25
public static MemoryAllocator Default { get ; } = Create ( ) ;
22
26
27
+ internal long MemoryGroupAllocationLimitBytes { get ; private set ; } = Environment . Is64BitProcess ?
28
+ 4L * OneGigabyte :
29
+ OneGigabyte ;
30
+
31
+ internal int SingleBufferAllocationLimitBytes { get ; private set ; } = OneGigabyte ;
32
+
23
33
/// <summary>
24
34
/// Gets the length of the largest contiguous buffer that can be handled by this allocator instance in bytes.
25
35
/// </summary>
@@ -30,16 +40,24 @@ public abstract class MemoryAllocator
30
40
/// Creates a default instance of a <see cref="MemoryAllocator"/> optimized for the executing platform.
31
41
/// </summary>
32
42
/// <returns>The <see cref="MemoryAllocator"/>.</returns>
33
- public static MemoryAllocator Create ( ) =>
34
- new UniformUnmanagedMemoryPoolMemoryAllocator ( null ) ;
43
+ public static MemoryAllocator Create ( ) => Create ( default ) ;
35
44
36
45
/// <summary>
37
46
/// Creates the default <see cref="MemoryAllocator"/> using the provided options.
38
47
/// </summary>
39
48
/// <param name="options">The <see cref="MemoryAllocatorOptions"/>.</param>
40
49
/// <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
+ }
43
61
44
62
/// <summary>
45
63
/// 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()
69
87
/// <param name="options">The <see cref="AllocationOptions"/>.</param>
70
88
/// <returns>A new <see cref="MemoryGroup{T}"/>.</returns>
71
89
/// <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 > (
73
91
long totalLength ,
74
92
int bufferAlignment ,
75
93
AllocationOptions options = AllocationOptions . None )
76
94
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 ) ;
78
117
}
0 commit comments