Browse Source

Bring back blob disposal checks

pull/8183/head
Max Katz 4 years ago
parent
commit
19ebf5ad7d
  1. 64
      src/Avalonia.Base/Platform/Internal/UnmanagedBlob.cs

64
src/Avalonia.Base/Platform/Internal/UnmanagedBlob.cs

@ -1,5 +1,8 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
namespace Avalonia.Platform.Internal;
@ -7,7 +10,30 @@ internal class UnmanagedBlob : IUnmanagedBlob
{
private IntPtr _address;
private readonly object _lock = new object();
#if DEBUG
private static readonly List<string> Backtraces = new List<string>();
private static Thread? GCThread;
private readonly string _backtrace;
private static readonly object _btlock = new object();
class GCThreadDetector
{
~GCThreadDetector()
{
GCThread = Thread.CurrentThread;
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
static void Spawn() => new GCThreadDetector();
static UnmanagedBlob()
{
Spawn();
GC.WaitForPendingFinalizers();
}
#endif
public UnmanagedBlob(int size)
{
try
@ -23,14 +49,23 @@ internal class UnmanagedBlob : IUnmanagedBlob
GC.SuppressFinalize(this);
throw;
}
#if DEBUG
_backtrace = Environment.StackTrace;
lock (_btlock)
Backtraces.Add(_backtrace);
#endif
}
private void DoDispose()
void DoDispose()
{
lock (_lock)
{
if (!IsDisposed)
{
#if DEBUG
lock (_btlock)
Backtraces.Remove(_backtrace);
#endif
Marshal.FreeHGlobal(_address);
GC.RemoveMemoryPressure(Size);
IsDisposed = true;
@ -39,18 +74,35 @@ internal class UnmanagedBlob : IUnmanagedBlob
}
}
}
public void Dispose()
{
#if DEBUG
if (Thread.CurrentThread.ManagedThreadId == GCThread?.ManagedThreadId)
{
lock (_lock)
{
if (!IsDisposed)
{
Console.Error.WriteLine("Native blob disposal from finalizer thread\nBacktrace: "
+ Environment.StackTrace
+ "\n\nBlob created by " + _backtrace);
}
}
}
#endif
DoDispose();
GC.SuppressFinalize(this);
}
~UnmanagedBlob()
{
#if DEBUG
Console.Error.WriteLine("Undisposed native blob created by " + _backtrace);
#endif
DoDispose();
}
public IntPtr Address => IsDisposed ? throw new ObjectDisposedException("UnmanagedBlob") : _address;
public int Size { get; private set; }
public bool IsDisposed { get; private set; }

Loading…
Cancel
Save