Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unmanaged pooling MemoryAllocator #1730

Merged
merged 96 commits into from
Dec 9, 2021
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
96 commits
Select commit Hold shift + click to select a range
7c1a1af
UniformUnmanagedMemoryPoolMemoryAllocator
antonfirsov Aug 7, 2021
ca17d33
use WeakReference with timer, configure trim period for sandbox
antonfirsov Aug 7, 2021
fd94dbf
fix trimming
antonfirsov Aug 7, 2021
1a41aaa
LoadResizeSaveParallelMemoryStress help text
antonfirsov Aug 8, 2021
aa26b63
Set_MaximumPoolSizeMegabytes_CreateImage_MaximumPoolSizeMegabytes
antonfirsov Aug 8, 2021
172b0a0
MinimumContiguousBlockBytes -> MinimumContiguousBlockSizeBytes
antonfirsov Aug 8, 2021
4251eac
disable CA2015
antonfirsov Aug 8, 2021
c9d1396
comments and docs
antonfirsov Aug 8, 2021
e13edba
fix .NET Framework build error + a few warnings
antonfirsov Aug 8, 2021
0cdbf72
disable MemoryGroupFinalizer_ReturnsToPool on MacOS
antonfirsov Aug 8, 2021
20d6228
make MemoryGroupFinalizer_ReturnsToPool Windows-only
antonfirsov Aug 8, 2021
1a86d6d
try to mitigate 32 bit failures
antonfirsov Aug 8, 2021
32ae7cf
API chunks
antonfirsov Aug 14, 2021
5dd8594
retry allocation on OOM
antonfirsov Aug 16, 2021
f7d9d37
cleanup naming in UniformUnmanagedMemoryPool
antonfirsov Aug 16, 2021
017ee40
Merge branch 'master' into af/UniformUnmanagedMemoryPoolMemoryAllocat…
antonfirsov Oct 16, 2021
a67cb01
fix build after merge
antonfirsov Oct 16, 2021
e233b81
undo unsafe optimizations in ErrorDither
antonfirsov Oct 16, 2021
5839a5a
PreferContiguousImageBuffers implemented
antonfirsov Oct 28, 2021
2472c42
MemoryAllocatorOptions -> MemoryAllocatorSettings,
antonfirsov Oct 28, 2021
3740471
MemoryAllocator.Create & tests
antonfirsov Oct 28, 2021
003e51e
MemoryAllocator.Default
antonfirsov Oct 28, 2021
f81008e
ProcessPixelRows tests
antonfirsov Oct 28, 2021
ce1ac2c
pass pinnable correctly
antonfirsov Oct 28, 2021
1df9e25
ProcessPixelRows
antonfirsov Oct 30, 2021
409cfb1
DangerousGetPixelRowMemory
antonfirsov Oct 30, 2021
e1f15bc
TryGetSinglePixelSpan -> DangerousTryGetSinglePixelMemory
antonfirsov Oct 30, 2021
f178416
test ImageFrame.DangerousGetPixelRowMemory
antonfirsov Oct 30, 2021
ff383c9
Buffer2D.GetRowSpan -> DangerousGetRowSpan
antonfirsov Oct 30, 2021
fb57101
Merge remote-tracking branch 'origin/master' into af/UniformUnmanaged…
antonfirsov Oct 30, 2021
64a9d25
update webp code
antonfirsov Oct 30, 2021
9047fc9
remove ImageFrame.GetPixelRowSpan
antonfirsov Oct 30, 2021
ebe7b9c
Remove Image.DangerousGetRowSpan
antonfirsov Oct 30, 2021
f40fc3a
test exception safety of ProcessPixelRows
antonfirsov Oct 30, 2021
251af06
Merge branch 'master' into af/UniformUnmanagedMemoryPoolMemoryAllocat…
antonfirsov Nov 7, 2021
58a23cd
remove ArrayPoolMemoryAllocator from tests
antonfirsov Nov 7, 2021
74d8be6
fix warning & simplify ClearTransparentPixels
antonfirsov Nov 7, 2021
412ebfb
Remove ArrayPoolMemoryAllocator
antonfirsov Nov 7, 2021
2d6596f
CopyPixelDataTo
antonfirsov Nov 7, 2021
8dda1d5
make GetNetCoreVersion work with preview
antonfirsov Nov 7, 2021
7186767
Disable MemoryAllocator_Create_LimitPoolSize on OSX
antonfirsov Nov 7, 2021
14eef74
Use [ConditionalFact] instead of [PlatformSpecific]
antonfirsov Nov 8, 2021
a9786b8
Merge branch 'master' into af/UniformUnmanagedMemoryPoolMemoryAllocat…
antonfirsov Nov 8, 2021
d09108a
fix test bug in WrapSystemDrawingBitmap_FromBytes_WhenObserved
antonfirsov Nov 8, 2021
2b6d940
update LoadResizeSaveParallelMemoryStress
antonfirsov Nov 9, 2021
7818ae0
temporarily remove try-catch in ImageProcessor<TPixel>.Apply()
antonfirsov Nov 13, 2021
f7b5807
(temporarily?) add RunTestsInLoop.ps1
antonfirsov Nov 13, 2021
bc70d10
Merge branch 'master' into af/UniformUnmanagedMemoryPoolMemoryAllocat…
antonfirsov Nov 13, 2021
bfcb1be
Logging made optional in TestMemoryAllocator
antonfirsov Nov 13, 2021
34a39e5
Relax criteria for Shuffle3
antonfirsov Nov 13, 2021
5c9be36
attempt to fix MemoryAllocator_Create_LimitPoolSize
antonfirsov Nov 13, 2021
ab0480f
memory clearing should not be UniformUnmanagedMemoryPool concern
antonfirsov Nov 19, 2021
ad982c4
emulate leaks in LoadResizeSaveParallelMemoryStress
antonfirsov Nov 19, 2021
5797197
MemoryOwnerFinalizer_ReturnsToPool
antonfirsov Nov 19, 2021
aaacc41
Add missing GC.SuppressFinalize(this)
antonfirsov Nov 19, 2021
27ede23
fixes
antonfirsov Nov 20, 2021
432c03a
remove outdated AllocationOptions.Contiguous
antonfirsov Nov 20, 2021
2b209f0
Merge remote-tracking branch 'origin/master' into af/UniformUnmanaged…
antonfirsov Nov 24, 2021
77e7700
Reimplement buffer ownership management
antonfirsov Nov 24, 2021
b43e963
stress testing improvements
antonfirsov Nov 24, 2021
b685d37
re-enable tests on Unix
antonfirsov Nov 24, 2021
b0b56df
wait a bit more in trim tests
antonfirsov Nov 24, 2021
13a3522
fix tests
antonfirsov Nov 24, 2021
916b31c
Disable MultiplePoolInstances_TrimPeriodElapsed_AllAreTrimmed on MacO…
antonfirsov Nov 25, 2021
d045df2
implement pool finalization & cleanup
antonfirsov Nov 25, 2021
a827390
Docs and null check on Configuration.MemoryAllocator.
antonfirsov Nov 25, 2021
452f31c
Disable RentReturnRelease_SubsequentRentReturnsDifferentHandles on Mac.
antonfirsov Nov 25, 2021
0de983b
Merge branch 'master' into af/UniformUnmanagedMemoryPoolMemoryAllocat…
antonfirsov Nov 25, 2021
308676e
promote Debug-InnerLoop hack
antonfirsov Nov 25, 2021
62943a1
Merge branch 'master' into af/UniformUnmanagedMemoryPoolMemoryAllocat…
antonfirsov Nov 25, 2021
4865ada
cleanup & comments
antonfirsov Nov 25, 2021
8c39628
make MemoryAllocatorSettings a struct
antonfirsov Nov 25, 2021
42546d0
nits
antonfirsov Nov 25, 2021
a02d88a
address some unrelated coverage issues reported by CodeCov for some r…
antonfirsov Nov 25, 2021
a3a6d1d
Always disable MultiplePoolInstances_TrimPeriodElapsed_AllAreTrimmed …
antonfirsov Nov 25, 2021
7ec7447
fix DetectEncoder tests
antonfirsov Nov 25, 2021
9ec8dc7
remove processor exception wrapping forever, fixes #1827
antonfirsov Nov 26, 2021
e10126e
use standard NETCOREAPP3_1_OR_GREATER directive
antonfirsov Nov 26, 2021
ee3265c
add back unsafe optimizations in ErrorDither
antonfirsov Nov 26, 2021
a57250e
oops
antonfirsov Nov 26, 2021
9f55e3f
fix comment
antonfirsov Nov 26, 2021
adaa67e
Merge branch 'master' into af/UniformUnmanagedMemoryPoolMemoryAllocat…
JimBobSquarePants Nov 29, 2021
f10da94
MemoryAllocatorSettings -> MemoryAllocatorOptions
antonfirsov Dec 4, 2021
751fc06
update shared-infrastructure
antonfirsov Dec 4, 2021
66967ab
Merge branch 'master' into af/UniformUnmanagedMemoryPoolMemoryAllocat…
antonfirsov Dec 4, 2021
d35b239
automatic consequence of shared-infrastructure update?
antonfirsov Dec 4, 2021
90316a1
serialize MultiplePoolInstances_TrimPeriodElapsed_AllAreTrimmed
antonfirsov Dec 4, 2021
7eaa5ee
attempt to re-enable MultiplePoolInstances_TrimPeriodElapsed_AllAreTr…
antonfirsov Dec 4, 2021
c90993b
Comments on [Theory] data
antonfirsov Dec 7, 2021
01f055a
Revert "attempt to re-enable MultiplePoolInstances_TrimPeriodElapsed_…
antonfirsov Dec 7, 2021
4986c52
Address local failures caused by high memory load
antonfirsov Dec 7, 2021
5b8be24
Merge branch 'master' into af/UniformUnmanagedMemoryPoolMemoryAllocat…
antonfirsov Dec 7, 2021
64d11ee
Merge branch 'af/UniformUnmanagedMemoryPoolMemoryAllocator-02' of htt…
antonfirsov Dec 7, 2021
53726f5
Merge branch 'master' into af/UniformUnmanagedMemoryPoolMemoryAllocat…
antonfirsov Dec 8, 2021
1e24da4
improve test naming
antonfirsov Dec 9, 2021
5eaa632
Merge branch 'af/UniformUnmanagedMemoryPoolMemoryAllocator-02' of htt…
antonfirsov Dec 9, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,7 @@
<Optimize>true</Optimize>
</PropertyGroup>

<PropertyGroup>
<DefineConstants Condition="$([MSBuild]::IsTargetFrameworkCompatible('$(TargetFramework)','netcoreapp3.1'))">$(DefineConstants);NETCORE31COMPATIBLE</DefineConstants>
antonfirsov marked this conversation as resolved.
Show resolved Hide resolved
</PropertyGroup>
</Project>
2 changes: 1 addition & 1 deletion src/ImageSharp/Advanced/AotCompilerTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@ private static void AotCompileDither<TPixel, TDither>()
private static void AotCompileMemoryManagers<TPixel>()
where TPixel : unmanaged, IPixel<TPixel>
{
AotCompileMemoryManager<TPixel, ArrayPoolMemoryAllocator>();
AotCompileMemoryManager<TPixel, UniformUnmanagedMemoryPoolMemoryAllocator>();
AotCompileMemoryManager<TPixel, SimpleGcMemoryAllocator>();
}

Expand Down
2 changes: 1 addition & 1 deletion src/ImageSharp/Configuration.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public int StreamProcessingBufferSize
/// <summary>
/// Gets or sets the <see cref="MemoryAllocator"/> that is currently in use.
/// </summary>
public MemoryAllocator MemoryAllocator { get; set; } = ArrayPoolMemoryAllocator.CreateDefault();
public MemoryAllocator MemoryAllocator { get; set; } = MemoryAllocator.CreateDefault();

/// <summary>
/// Gets the maximum header size of all the formats.
Expand Down
10 changes: 10 additions & 0 deletions src/ImageSharp/ImageFrame{TPixel}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,9 @@ internal ImageFrame(Configuration configuration, ImageFrame<TPixel> source)
/// <summary>
/// Gets the representation of the pixels as a <see cref="Span{T}"/> of contiguous memory
/// at row <paramref name="rowIndex"/> beginning from the first pixel on that row.
/// <para />
/// WARNING: Disposing or leaking the underlying image while still working with it's <see cref="Span{T}"/>
/// might lead to memory corruption.
/// </summary>
/// <param name="rowIndex">The row.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
Expand All @@ -185,6 +188,13 @@ public Span<TPixel> GetPixelRowSpan(int rowIndex)
/// <summary>
/// Gets the representation of the pixels as a <see cref="Span{T}"/> in the source image's pixel format
/// stored in row major order, if the backing buffer is contiguous.
/// <para />
/// To ensure the memory is contiguous, <see cref="Configuration.MemoryAllocator"/> should be initialized
/// with a <see cref="MemoryAllocator"/> that enforces larger contiguous buffers.
/// See <see cref="MemoryAllocatorOptions.MinimumContiguousBlockSizeBytes"/>.
/// <para />
/// WARNING: Disposing or leaking the underlying image while still working with it's <see cref="Span{T}"/>
/// might lead to memory corruption.
/// </summary>
/// <param name="span">The <see cref="Span{T}"/>.</param>
/// <returns>The <see cref="bool"/>.</returns>
Expand Down
2 changes: 1 addition & 1 deletion src/ImageSharp/ImageSharp.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
<PackageTags>Image Resize Crop Gif Jpg Jpeg Bitmap Png Tga NetCore</PackageTags>
<Description>A new, fully featured, fully managed, cross-platform, 2D graphics API for .NET</Description>
<Configurations>Debug;Release;Debug-InnerLoop;Release-InnerLoop</Configurations>
<DefineConstants Condition="'$(Configuration)' == 'Debug-InnerLoop'">$(DefineConstants);DEBUG</DefineConstants>
antonfirsov marked this conversation as resolved.
Show resolved Hide resolved
</PropertyGroup>

<Choose>
<When Condition="$(SIXLABORS_TESTING) == true">
<PropertyGroup>
Expand Down
3 changes: 3 additions & 0 deletions src/ImageSharp/Image{TPixel}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,9 @@ internal Image(Configuration configuration, ImageMetadata metadata, IEnumerable<
/// <summary>
/// Gets the representation of the pixels as a <see cref="Span{T}"/> of contiguous memory
/// at row <paramref name="rowIndex"/> beginning from the first pixel on that row.
/// <para />
/// WARNING: Disposing or leaking the underlying image while still working with it's <see cref="Span{T}"/>
/// might lead to memory corruption.
/// </summary>
/// <param name="rowIndex">The row.</param>
/// <returns>The <see cref="Span{TPixel}"/></returns>
Expand Down
3 changes: 3 additions & 0 deletions src/ImageSharp/IndexedImageFrame{TPixel}.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,9 @@ internal IndexedImageFrame(Configuration configuration, int width, int height, R
/// <summary>
/// Gets the representation of the pixels as a <see cref="ReadOnlySpan{T}"/> of contiguous memory
/// at row <paramref name="rowIndex"/> beginning from the first pixel on that row.
/// <para />
/// WARNING: Disposing or leaking the underlying <see cref="IndexedImageFrame{TPixel}"/> while still working with it's <see cref="Span{T}"/>
/// might lead to memory corruption.
/// </summary>
/// <param name="rowIndex">The row index in the pixel buffer.</param>
/// <returns>The pixel row as a <see cref="ReadOnlySpan{T}"/>.</returns>
Expand Down
13 changes: 11 additions & 2 deletions src/ImageSharp/Memory/Allocators/AllocationOptions.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,30 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.

using System;

namespace SixLabors.ImageSharp.Memory
{
/// <summary>
/// Options for allocating buffers.
/// </summary>
[Flags]
public enum AllocationOptions
{
/// <summary>
/// Indicates that the buffer should just be allocated.
/// </summary>
None,
None = 0,

/// <summary>
/// Indicates that the allocated buffer should be cleaned following allocation.
/// </summary>
Clean
Clean = 1,

/// <summary>
/// Affects only group allocations.
/// Indicates that the requested <see cref="MemoryGroup{T}"/> or <see cref="Buffer2D{T}"/> should be made of contiguous blocks up to <see cref="int.MaxValue"/>.
/// </summary>
Contiguous = 2
}
}
10 changes: 10 additions & 0 deletions src/ImageSharp/Memory/Allocators/AllocationOptionsExtensions.cs
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
namespace SixLabors.ImageSharp.Memory
{
/// <summary>
/// Contains <see cref="Buffer{T}"/> and <see cref="ManagedByteBuffer"/>.
/// Contains <see cref="Buffer{T}"/>.
/// </summary>
public partial class ArrayPoolMemoryAllocator
{
Expand Down Expand Up @@ -87,19 +87,5 @@ private static void ThrowObjectDisposedException()
throw new ObjectDisposedException("ArrayPoolMemoryAllocator.Buffer<T>");
}
}

/// <summary>
/// The <see cref="IManagedByteBuffer"/> implementation of <see cref="ArrayPoolMemoryAllocator"/>.
/// </summary>
private sealed class ManagedByteBuffer : Buffer<byte>, IManagedByteBuffer
{
public ManagedByteBuffer(byte[] data, int length, ArrayPool<byte> sourcePool)
: base(data, length, sourcePool)
{
}

/// <inheritdoc />
public byte[] Array => this.Data;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public partial class ArrayPoolMemoryAllocator
/// This is the default. Should be good for most use cases.
/// </summary>
/// <returns>The memory manager.</returns>
public static ArrayPoolMemoryAllocator CreateDefault()
public static new ArrayPoolMemoryAllocator CreateDefault()
{
return new ArrayPoolMemoryAllocator(
DefaultMaxPooledBufferSizeInBytes,
Expand Down
25 changes: 3 additions & 22 deletions src/ImageSharp/Memory/Allocators/ArrayPoolMemoryAllocator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace SixLabors.ImageSharp.Memory
/// <summary>
/// Implements <see cref="MemoryAllocator"/> by allocating memory from <see cref="ArrayPool{T}"/>.
/// </summary>
[Obsolete("ArrayPoolMemoryAllocator is obsolete. Use MemoryAllocator.CreateDefault() instead.")]
public sealed partial class ArrayPoolMemoryAllocator : MemoryAllocator
{
private readonly int maxArraysPerBucketNormalPool;
Expand Down Expand Up @@ -136,35 +137,15 @@ public override IMemoryOwner<T> Allocate<T>(int length, AllocationOptions option
byte[] byteArray = pool.Rent(bufferSizeInBytes);

var buffer = new Buffer<T>(byteArray, length, pool);
if (options == AllocationOptions.Clean)
if (options.Has(AllocationOptions.Clean))
{
buffer.GetSpan().Clear();
}

return buffer;
}

/// <inheritdoc />
public override IManagedByteBuffer AllocateManagedByteBuffer(int length, AllocationOptions options = AllocationOptions.None)
{
Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length));

ArrayPool<byte> 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<T>(int length, int max) =>
Expand Down
18 changes: 0 additions & 18 deletions src/ImageSharp/Memory/Allocators/IManagedByteBuffer.cs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
// Licensed under the Apache License, Version 2.0.

using System;
using System.Buffers;

namespace SixLabors.ImageSharp.Memory.Internals
{
/// <summary>
/// Wraps an array as an <see cref="IManagedByteBuffer"/> instance.
/// Wraps an array as an <see cref="MemoryManager{T}"/> instance.
/// </summary>
/// <inheritdoc />
internal class BasicArrayBuffer<T> : ManagedBufferBase<T>
Expand Down Expand Up @@ -57,4 +58,4 @@ protected override object GetPinnableObject()
return this.Array;
}
}
}
}
20 changes: 0 additions & 20 deletions src/ImageSharp/Memory/Allocators/Internals/BasicByteBuffer.cs

This file was deleted.

115 changes: 115 additions & 0 deletions src/ImageSharp/Memory/Allocators/Internals/Gen2GcCallback.cs
Original file line number Diff line number Diff line change
@@ -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
{
/// <summary>
/// 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)
/// </summary>
internal sealed class Gen2GcCallback : CriticalFinalizerObject
{
private readonly Func<bool> callback0;
private readonly Func<object, bool> callback1;
private GCHandle weakTargetObj;

private Gen2GcCallback(Func<bool> callback)
{
this.callback0 = callback;
}

private Gen2GcCallback(Func<object, bool> callback, object targetObj)
{
this.callback1 = callback;
this.weakTargetObj = GCHandle.Alloc(targetObj, GCHandleType.Weak);
}

~Gen2GcCallback()
{
if (this.weakTargetObj.IsAllocated)
{
// Check to see if the target object is still alive.
object targetObj = this.weakTargetObj.Target;
if (targetObj == null)
{
// The target object is dead, so this callback object is no longer needed.
this.weakTargetObj.Free();
return;
}

// Execute the callback method.
try
{
if (!this.callback1(targetObj))
{
// If the callback returns false, this callback object is no longer needed.
this.weakTargetObj.Free();
return;
}
}
catch
{
// Ensure that we still get a chance to resurrect this object, even if the callback throws an exception.
#if DEBUG
// Except in DEBUG, as we really shouldn't be hitting any exceptions here.
throw;
#endif
}
}
else
{
// Execute the callback method.
try
{
if (!this.callback0())
{
// If the callback returns false, this callback object is no longer needed.
return;
}
}
catch
{
// Ensure that we still get a chance to resurrect this object, even if the callback throws an exception.
#if DEBUG
// Except in DEBUG, as we really shouldn't be hitting any exceptions here.
throw;
#endif
}
}

// Resurrect ourselves by re-registering for finalization.
GC.ReRegisterForFinalize(this);
}

/// <summary>
/// Schedule 'callback' to be called in the next GC. If the callback returns true it is
/// rescheduled for the next Gen 2 GC. Otherwise the callbacks stop.
/// </summary>
public static void Register(Func<bool> callback)
{
// Create a unreachable object that remembers the callback function and target object.
_ = new Gen2GcCallback(callback);
}

/// <summary>
/// Schedule 'callback' to be called in the next GC. If the callback returns true it is
/// rescheduled for the next Gen 2 GC. Otherwise the callbacks stop.
///
/// NOTE: This callback will be kept alive until either the callback function returns false,
/// or the target object dies.
/// </summary>
public static void Register(Func<object, bool> callback, object targetObj)
{
// Create a unreachable object that remembers the callback function and target object.
_ = new Gen2GcCallback(callback, targetObj);
}
}
}
#endif
Loading