From b16e002706fa46ba0f6aa9a7e3fd1d024aeddc25 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 18 Jan 2018 02:59:46 +0100 Subject: [PATCH] Use 2 ArrayPool-s with different maxArrayPerBuckets parameters, so we never have more than 8 buckets for large buffers for a single value type. --- src/ImageSharp/Memory/PixelDataPool{T}.cs | 43 ++++++++++++++++--- .../Memory/PixelDataPoolTests.cs | 32 +++++++++----- 2 files changed, 57 insertions(+), 18 deletions(-) diff --git a/src/ImageSharp/Memory/PixelDataPool{T}.cs b/src/ImageSharp/Memory/PixelDataPool{T}.cs index f25803951..80c9c410e 100644 --- a/src/ImageSharp/Memory/PixelDataPool{T}.cs +++ b/src/ImageSharp/Memory/PixelDataPool{T}.cs @@ -17,17 +17,32 @@ namespace SixLabors.ImageSharp.Memory /// The maximum size of pooled arrays in bytes. /// Currently set to 32MB, which is equivalent to 8 megapixels of raw data. /// - private const int MaxPooledBufferSizeInBytes = 32 * 1024 * 1024; + internal const int MaxPooledBufferSizeInBytes = 32 * 1024 * 1024; /// - /// The maximum array length of the . + /// The threshold to pool arrays in which has less buckets for memory safety. /// - private static readonly int MaxArrayLength = MaxPooledBufferSizeInBytes / Unsafe.SizeOf(); + private const int LargeBufferThresholdInBytes = 8 * 1024 * 1024; /// - /// The which is not kept clean. + /// The maximum array length of the . /// - private static readonly ArrayPool ArrayPool = ArrayPool.Create(MaxArrayLength, 50); + private static readonly int MaxLargeArrayLength = MaxPooledBufferSizeInBytes / Unsafe.SizeOf(); + + /// + /// The maximum array length of the . + /// + private static readonly int MaxNormalArrayLength = LargeBufferThresholdInBytes / Unsafe.SizeOf(); + + /// + /// The for huge buffers, which is not kept clean. + /// + private static readonly ArrayPool LargeArrayPool = ArrayPool.Create(MaxLargeArrayLength, 8); + + /// + /// The for small-to-medium buffers which is not kept clean. + /// + private static readonly ArrayPool NormalArrayPool = ArrayPool.Create(MaxNormalArrayLength, 24); /// /// Rents the pixel array from the pool. @@ -36,7 +51,14 @@ namespace SixLabors.ImageSharp.Memory /// The public static T[] Rent(int minimumLength) { - return ArrayPool.Rent(minimumLength); + if (minimumLength <= MaxNormalArrayLength) + { + return NormalArrayPool.Rent(minimumLength); + } + else + { + return LargeArrayPool.Rent(minimumLength); + } } /// @@ -45,7 +67,14 @@ namespace SixLabors.ImageSharp.Memory /// The array to return to the buffer pool. public static void Return(T[] array) { - ArrayPool.Return(array); + if (array.Length <= MaxNormalArrayLength) + { + NormalArrayPool.Return(array); + } + else + { + LargeArrayPool.Return(array); + } } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Memory/PixelDataPoolTests.cs b/tests/ImageSharp.Tests/Memory/PixelDataPoolTests.cs index beaa49dbc..caba9a464 100644 --- a/tests/ImageSharp.Tests/Memory/PixelDataPoolTests.cs +++ b/tests/ImageSharp.Tests/Memory/PixelDataPoolTests.cs @@ -9,19 +9,25 @@ using Xunit; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Memory { + using System; + /// /// Tests the class. /// public class PixelDataPoolTests { + private const int MaxPooledBufferSizeInBytes = PixelDataPool.MaxPooledBufferSizeInBytes; + readonly object monitor = new object(); - [Fact] - public void PixelDataPoolRentsMinimumSize() + [Theory] + [InlineData(1)] + [InlineData(1024)] + public void PixelDataPoolRentsMinimumSize(int size) { - Rgba32[] pixels = PixelDataPool.Rent(1024); + Rgba32[] pixels = PixelDataPool.Rent(size); - Assert.True(pixels.Length >= 1024); + Assert.True(pixels.Length >= size); } [Fact] @@ -65,17 +71,21 @@ namespace SixLabors.ImageSharp.Tests.Memory } } - [Fact] - public void SmallBuffersArePooled() + [Theory] + [InlineData(32)] + [InlineData(512)] + [InlineData(MaxPooledBufferSizeInBytes-1)] + public void SmallBuffersArePooled(int size) { - Assert.True(this.CheckIsPooled(5, 512)); + Assert.True(this.CheckIsPooled(5, size)); } - [Fact] - public void LargeBuffersAreNotPooled_OfByte() + [Theory] + [InlineData(128 * 1024 * 1024)] + [InlineData(MaxPooledBufferSizeInBytes+1)] + public void LargeBuffersAreNotPooled_OfByte(int size) { - const int mb128 = 128 * 1024 * 1024; - Assert.False(this.CheckIsPooled(2, mb128)); + Assert.False(this.CheckIsPooled(2, size)); } [StructLayout(LayoutKind.Explicit, Size = 512)]