Skip to content

Memory Leak from CanvasBitmap #1009

@solocle

Description

@solocle

Saw this as a major issue in a production project, rising to 40GB of commit charge in half an hour.

The issue seems to be hardware-linked, as it doesn't seem occur on an Nvidia RTX, but does on Intel Arc A40.

Minimum reproduction:

New UWP .NET 9 project (also seen in .NET Native)

MainPage.xaml

<Page
    x:Class="CanvasMemoryLeak.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:CanvasMemoryLeak"
    xmlns:win2d="using:Microsoft.Graphics.Canvas.UI.Xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <win2d:CanvasAnimatedControl x:Name="Leaky" Draw="Leaky_Draw" Update="Leaky_Update" />
</Page>

MainPage.xaml.cs

using Windows.UI.Xaml.Controls;
using Microsoft.Graphics.Canvas.UI.Xaml;
using Windows.UI;
using System.Runtime.InteropServices.WindowsRuntime;
using Microsoft.Graphics.Canvas;
using System;
using Microsoft.Graphics.Canvas.Effects;

namespace CanvasMemoryLeak
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a <see cref="Frame">.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        public MainPage()
        {
            InitializeComponent();
            Buffer = new byte[WIDTH * HEIGHT];
            Buffer.AsSpan().Fill(127);

        }

        private const ushort WIDTH = 640;
        private const ushort HEIGHT = 480;

        private byte[] Buffer;

        private static readonly ColorSourceEffect White = new ColorSourceEffect() { Color = Colors.White };
        private static readonly ColorSourceEffect Black = new ColorSourceEffect() { Color = Colors.Black };

        private void Leaky_Draw(ICanvasAnimatedControl sender, CanvasAnimatedDrawEventArgs args)
        {
            var ds = args.DrawingSession;
            ds.Clear(Colors.Black);
            var source = Buffer.AsBuffer();
            using (var bmp = CanvasBitmap.CreateFromBytes(ds,source, WIDTH, HEIGHT, Windows.Graphics.DirectX.DirectXPixelFormat.A8UIntNormalized))
            {
                using(var alpha = new AlphaMaskEffect() { Source = White, AlphaMask = bmp })
                {
                    using (var blend = new BlendEffect() { Foreground = alpha, Background = Black, Mode = BlendEffectMode.Screen })
                        ds.DrawImage(blend);
                }
            }
        }

        private void Leaky_Update(ICanvasAnimatedControl sender, CanvasAnimatedUpdateEventArgs args)
        {
            var random = new Random();
            for (int pos = 0; pos < Buffer.Length; pos++)
            {
                int value = Buffer[pos];
                value += random.Next(-10, 10);
                Buffer[pos] = (byte)Math.Clamp(value, 0, 255);
            }
        }
    }
}
`

System Configuration:
i7-14700
32GB RAM
Intel Arc Pro A40 driver 32.0.101.6979

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions