Просмотр исходного кода

Improved unmanaged memory allocation diagnostics. ref #1411

Nikita Tsukanov 7 лет назад
Родитель
Сommit
77b74444ba

+ 3 - 2
src/Gtk/Avalonia.Gtk3/FramebufferManager.cs

@@ -26,8 +26,9 @@ namespace Avalonia.Gtk3
         {
             // This method may be called from non-UI thread, don't touch anything that calls back to GTK/GDK
             var s = _window.ClientSize;
-            var width = (int) s.Width;
-            var height = (int) s.Height;
+            var width = Math.Max(1, (int) s.Width);
+            var height = Math.Max(1, (int) s.Height);
+            
             
             if (!Dispatcher.UIThread.CheckAccess() && Gtk3Platform.DisplayClassName.ToLower().Contains("x11"))
             {

+ 5 - 5
src/OSX/Avalonia.MonoMac/EmulatedFramebuffer.cs

@@ -12,6 +12,7 @@ namespace Avalonia.MonoMac
         private readonly TopLevelImpl.TopLevelView _view;
         private readonly CGSize _logicalSize;
         private readonly bool _isDeferred;
+        private readonly IUnmanagedBlob _blob;
 
         [DllImport("libc")]
         static extern void memset(IntPtr p, int c, IntPtr size);
@@ -29,13 +30,13 @@ namespace Avalonia.MonoMac
             Dpi = new Vector(96 * pixelSize.Width / _logicalSize.Width, 96 * pixelSize.Height / _logicalSize.Height);
             Format = PixelFormat.Rgba8888;
             var size = Height * RowBytes;
-            Address = Marshal.AllocHGlobal(size);
+            _blob = AvaloniaLocator.Current.GetService<IRuntimePlatform>().AllocBlob(size);
             memset(Address, 0, new IntPtr(size));
         }
         
         public void Dispose()
         {
-            if (Address == IntPtr.Zero)
+            if (_blob.IsDisposed)
                 return;
             var nfo = (int) CGBitmapFlags.ByteOrder32Big | (int) CGImageAlphaInfo.PremultipliedLast;
             CGImage image = null;
@@ -71,14 +72,13 @@ namespace Avalonia.MonoMac
                     else
                         _view.SetBackBufferImage(new SavedImage(image, _logicalSize));
                 }
-                Marshal.FreeHGlobal(Address);
-                Address = IntPtr.Zero;
+                _blob.Dispose();
             }
 
 
         }
 
-        public IntPtr Address { get; private set; }
+        public IntPtr Address => _blob.Address;
         public int Width { get; }
         public int Height { get; }
         public int RowBytes { get; }

+ 20 - 11
src/Shared/PlatformSupport/StandardRuntimePlatform.cs

@@ -28,11 +28,13 @@ namespace Avalonia.Shared.PlatformSupport
         class UnmanagedBlob : IUnmanagedBlob
         {
             private readonly StandardRuntimePlatform _plat;
+            private IntPtr _address;
 #if DEBUG
             private static readonly List<string> Backtraces = new List<string>();
             private static Thread GCThread;
             private readonly string _backtrace;
-
+            private readonly object _lock = new object();
+            private static readonly object _btlock = new object();
 
             class GCThreadDetector
             {
@@ -55,28 +57,35 @@ namespace Avalonia.Shared.PlatformSupport
             
             public UnmanagedBlob(StandardRuntimePlatform plat, int size)
             {
+                if (size <= 0)
+                    throw new ArgumentException("Positive number required", nameof(size));
                 _plat = plat;
-                Address = plat.Alloc(size);
+                _address = plat.Alloc(size);
                 GC.AddMemoryPressure(size);
                 Size = size;
 #if DEBUG
                 _backtrace = Environment.StackTrace;
-                Backtraces.Add(_backtrace);
+                lock (_btlock)
+                    Backtraces.Add(_backtrace);
 #endif
             }
 
             void DoDispose()
             {
-                if (!IsDisposed)
+                lock (_lock)
                 {
+                    if (!IsDisposed)
+                    {
 #if DEBUG
-                    Backtraces.Remove(_backtrace);
+                        lock (_btlock)
+                            Backtraces.Remove(_backtrace);
 #endif
-                    _plat.Free(Address, Size);
-                    GC.RemoveMemoryPressure(Size);
-                    IsDisposed = true;
-                    Address = IntPtr.Zero;
-                    Size = 0;
+                        _plat.Free(_address, Size);
+                        GC.RemoveMemoryPressure(Size);
+                        IsDisposed = true;
+                        _address = IntPtr.Zero;
+                        Size = 0;
+                    }
                 }
             }
 
@@ -102,7 +111,7 @@ namespace Avalonia.Shared.PlatformSupport
                 DoDispose();
             }
 
-            public IntPtr Address { get; private set; }
+            public IntPtr Address => IsDisposed ? throw new ObjectDisposedException("UnmanagedBlob") : _address; 
             public int Size { get; private set; }
             public bool IsDisposed { get; private set; }
         }

+ 6 - 16
src/Windows/Avalonia.Win32/WindowFramebuffer.cs

@@ -10,7 +10,7 @@ namespace Avalonia.Win32
     public class WindowFramebuffer : ILockedFramebuffer
     {
         private readonly IntPtr _handle;
-        private IntPtr _pBitmap;
+        private IUnmanagedBlob _bitmapBlob;
         private UnmanagedMethods.BITMAPINFOHEADER _bmpInfo;
 
         public WindowFramebuffer(IntPtr handle, int width, int height)
@@ -27,7 +27,7 @@ namespace Avalonia.Win32
             _bmpInfo.Init();
             _bmpInfo.biWidth = width;
             _bmpInfo.biHeight = -height;
-            _pBitmap = Marshal.AllocHGlobal(width * height * 4);
+            _bitmapBlob = AvaloniaLocator.Current.GetService<IRuntimePlatform>().AllocBlob(width * height * 4);
         }
 
         ~WindowFramebuffer()
@@ -35,7 +35,7 @@ namespace Avalonia.Win32
             Deallocate();
         }
 
-        public IntPtr Address => _pBitmap;
+        public IntPtr Address => _bitmapBlob.Address;
         public int RowBytes => Width * 4;
         public PixelFormat Format => PixelFormat.Bgra8888;
 
@@ -70,21 +70,18 @@ namespace Avalonia.Win32
         public void DrawToDevice(IntPtr hDC, int destX = 0, int destY = 0, int srcX = 0, int srcY = 0, int width = -1,
             int height = -1)
         {
-            if(_pBitmap == IntPtr.Zero)
-                throw new ObjectDisposedException("Framebuffer");
             if (width == -1)
                 width = Width;
             if (height == -1)
                 height = Height;
             UnmanagedMethods.SetDIBitsToDevice(hDC, destX, destY, (uint) width, (uint) height, srcX, srcY,
-                0, (uint)Height, _pBitmap, ref _bmpInfo, 0);
+                0, (uint)Height, _bitmapBlob.Address, ref _bmpInfo, 0);
         }
 
         public bool DrawToWindow(IntPtr hWnd, int destX = 0, int destY = 0, int srcX = 0, int srcY = 0, int width = -1,
             int height = -1)
         {
-
-            if (_pBitmap == IntPtr.Zero)
+            if (_bitmapBlob.IsDisposed)
                 throw new ObjectDisposedException("Framebuffer");
             if (hWnd == IntPtr.Zero)
                 return false;
@@ -102,13 +99,6 @@ namespace Avalonia.Win32
             DrawToWindow(_handle);
         }
 
-        public void Deallocate()
-        {
-            if (_pBitmap != IntPtr.Zero)
-            {
-                Marshal.FreeHGlobal(_pBitmap);
-                _pBitmap = IntPtr.Zero;
-            }
-        }
+        public void Deallocate() => _bitmapBlob.Dispose();
     }
 }