Browse Source

use WeakReference with timer, configure trim period for sandbox

af/UniformUnmanagedMemoryPoolMemoryAllocator-02-MemoryGuards
Anton Firszov 5 years ago
parent
commit
ca17d33ea3
  1. 15
      src/ImageSharp/Memory/Allocators/Internals/UniformUnmanagedMemoryPool.cs
  2. 22
      src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs
  3. 10
      tests/ImageSharp.Tests.ProfilingSandbox/LoadResizeSaveParallelMemoryStress.cs

15
src/ImageSharp/Memory/Allocators/Internals/UniformUnmanagedMemoryPool.cs

@ -34,9 +34,10 @@ namespace SixLabors.ImageSharp.Memory.Internals
// Invoke the timer callback more frequently, than trimSettings.TrimPeriodMilliseconds,
// and also invoke it on Gen 2 GC.
// We are checking in the callback if enough time passed since the last trimming. If not, we do nothing.
var weakPoolRef = new WeakReference<UniformUnmanagedMemoryPool>(this);
this.trimTimer = new Timer(
s => ((UniformUnmanagedMemoryPool)s)?.Trim(),
this,
s => TimerCallback((WeakReference<UniformUnmanagedMemoryPool>)s),
weakPoolRef,
this.trimSettings.TrimPeriodMilliseconds / 4,
this.trimSettings.TrimPeriodMilliseconds / 4);
@ -217,6 +218,14 @@ namespace SixLabors.ImageSharp.Memory.Internals
private static void ThrowReturnedMoreArraysThanRented() =>
throw new InvalidMemoryOperationException("Returned more arrays then rented");
private static void TimerCallback(WeakReference<UniformUnmanagedMemoryPool> weakPoolRef)
{
if (weakPoolRef.TryGetTarget(out UniformUnmanagedMemoryPool pool))
{
pool.Trim();
}
}
private bool Trim()
{
UnmanagedMemoryHandle[] buffersLocal = this.buffers;
@ -307,7 +316,7 @@ namespace SixLabors.ImageSharp.Memory.Internals
public class TrimSettings
{
// Trim half of the retained pool buffers every minute.
public int TrimPeriodMilliseconds { get; set; } = 60_000;
public int TrimPeriodMilliseconds { get; set; } = 20_000;
public float Rate { get; set; } = 0.5f;

22
src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs

@ -18,6 +18,7 @@ namespace SixLabors.ImageSharp.Memory
private readonly int sharedArrayPoolThresholdInBytes;
private readonly int poolBufferSizeInBytes;
private readonly int poolCapacity;
private readonly UniformUnmanagedMemoryPool.TrimSettings trimSettings;
private UniformUnmanagedMemoryPool pool;
private readonly UnmanagedMemoryAllocator nonPoolAllocator;
@ -42,17 +43,32 @@ namespace SixLabors.ImageSharp.Memory
{
}
// Internal constructor allowing to change the shared array pool threshold for testing purposes.
internal UniformUnmanagedMemoryPoolMemoryAllocator(
int sharedArrayPoolThresholdInBytes,
int poolBufferSizeInBytes,
long maxPoolSizeInBytes,
int unmanagedBufferSizeInBytes)
: this(
sharedArrayPoolThresholdInBytes,
poolBufferSizeInBytes,
maxPoolSizeInBytes,
unmanagedBufferSizeInBytes,
UniformUnmanagedMemoryPool.TrimSettings.Default)
{
}
internal UniformUnmanagedMemoryPoolMemoryAllocator(
int sharedArrayPoolThresholdInBytes,
int poolBufferSizeInBytes,
long maxPoolSizeInBytes,
int unmanagedBufferSizeInBytes,
UniformUnmanagedMemoryPool.TrimSettings trimSettings)
{
this.sharedArrayPoolThresholdInBytes = sharedArrayPoolThresholdInBytes;
this.poolBufferSizeInBytes = poolBufferSizeInBytes;
this.poolCapacity = (int)(maxPoolSizeInBytes / poolBufferSizeInBytes);
this.pool = new UniformUnmanagedMemoryPool(this.poolBufferSizeInBytes, this.poolCapacity);
this.trimSettings = trimSettings;
this.pool = new UniformUnmanagedMemoryPool(this.poolBufferSizeInBytes, this.poolCapacity, this.trimSettings);
this.nonPoolAllocator = new UnmanagedMemoryAllocator(unmanagedBufferSizeInBytes);
}
@ -125,7 +141,7 @@ namespace SixLabors.ImageSharp.Memory
{
UniformUnmanagedMemoryPool oldPool = Interlocked.Exchange(
ref this.pool,
new UniformUnmanagedMemoryPool(this.poolBufferSizeInBytes, this.poolCapacity));
new UniformUnmanagedMemoryPool(this.poolBufferSizeInBytes, this.poolCapacity, this.trimSettings));
oldPool.Release();
}

10
tests/ImageSharp.Tests.ProfilingSandbox/LoadResizeSaveParallelMemoryStress.cs

@ -11,6 +11,7 @@ using System.Threading;
using CommandLine;
using SixLabors.ImageSharp.Benchmarks.LoadResizeSave;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Memory.Internals;
namespace SixLabors.ImageSharp.Tests.ProfilingSandbox
{
@ -231,6 +232,9 @@ namespace SixLabors.ImageSharp.Tests.ProfilingSandbox
[Option('f', "file", Required = false, Default = null)]
public string FileOutput { get; set; }
[Option('t', "trim-time", Required = false, Default = 60)]
public int TrimTimeSeconds { get; set; }
public static CommandLineOptions Parse(string[] args)
{
CommandLineOptions result = null;
@ -257,7 +261,11 @@ namespace SixLabors.ImageSharp.Tests.ProfilingSandbox
1024 * 1024,
(int)B(this.MaxContiguousPoolBufferMegaBytes),
B(this.MaxPoolSizeMegaBytes),
(int)B(this.MaxCapacityOfUnmanagedBuffersMegaBytes));
(int)B(this.MaxCapacityOfUnmanagedBuffersMegaBytes),
new UniformUnmanagedMemoryPool.TrimSettings
{
TrimPeriodMilliseconds = this.TrimTimeSeconds * 100
});
default:
throw new ArgumentOutOfRangeException();
}

Loading…
Cancel
Save