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

Known issue: WPF Image memory leak when remove image from visual tree #2397

Open
lindexi opened this issue Jan 5, 2020 · 5 comments
Open
Assignees
Labels
Bug Product bug (most likely) .NET Framework Performance Performance related issue
Milestone

Comments

@lindexi
Copy link
Member

lindexi commented Jan 5, 2020

  • .NET Core Version: 3.1.100
  • Windows version: 18363
  • Does the bug reproduce also in WPF for .NET Framework 4.8?: Yes
  • Is this bug related specifically to tooling in Visual Studio No

Problem description:

The image source will memory leak when we remove the image from visual tree before we set the image source as null

Step:

  1. Set the image source
  2. Add image in the VisualTree and wait the image show
  3. Remove image from the visual tree and then set the image source as null

And you can find the image source object never free

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            // Remove the current Image control from the  visual tree and set source is null when click button.
            // Then new a image control and add source to the RenderTargetBitmap object and show it.
            // You can see the gc never delete the RenderTargetBitmap object that make  memory leak.

            var oldBorder = RootGrid.Children.OfType<Border>().LastOrDefault();
            if (oldBorder != null)
            {
                var oldImage = (Image)oldBorder.Child;

                // In order to solve it , you should set the image.Source is null and use UpdateLayout.
                // The below code can solve it.
                // oldImage.Source = null;
                // oldImage.UpdateLayout();

                // Remove the current Image control from the  visual tree.
                RootGrid.Children.Remove(oldBorder);
                oldImage.Source = null;
                Borders.Add(oldBorder);
            }

            var bitmap = new RenderTargetBitmap(1024, 1024, 96, 96, PixelFormats.Default);

            var image = new Image { Source = bitmap };
            var border = new Border { Child = image };
            RootGrid.Children.Add(border);

            // In order to facilitate changes in memory, after each operation will be garbage collection
            GC.Collect();
        }

        public readonly List<Border> Borders = new List<Border>();

Actual behavior:

The Image memory leak

Expected behavior:

The image source object can be free

Minimal repro:

https://github.com/dotnet-campus/wpf-issues/tree/master/ImageMemoryLeakDotNetCore

@lindexi
Copy link
Member Author

lindexi commented Jan 5, 2020

How to solve it?

In order to solve it , you should set the image.Source is null and use UpdateLayout.

The below code can solve it.

            oldImage.Source = null;
            oldImage.UpdateLayout();

@lindexi
Copy link
Member Author

lindexi commented Jan 5, 2020

Why the image will memory leak?

Because the Image use RenderData class to storage the image source object and the UIElement._drawingContent will reference the RenderData.

The image will never re-render when we remove the image from the visual tree and the RenderData will never update.

Why we set the image source as null and then update layout can solve?

Because the image source is null and the update layout will call render to update the _drawingContent to the new RenderData which does not storage the image source object (or it stroage a null object)

@gomathip02 gomathip02 added this to the 5.0 milestone Jan 7, 2020
@gomathip02 gomathip02 added the Bug Product bug (most likely) label Jan 7, 2020
@ryalanms ryalanms modified the milestones: 5.0.0, 7.0.0 Aug 26, 2021
@meJevin
Copy link

meJevin commented Oct 27, 2021

@lindexi, you are amazing! Thank you so much for providing a solution as well as an explanation!

@pchaurasia14 pchaurasia14 changed the title Known issus: WPF Image memory leak when remove image from visual tree Known issue: WPF Image memory leak when remove image from visual tree Oct 6, 2022
@Kuldeep-MS Kuldeep-MS self-assigned this Oct 10, 2022
@Kuldeep-MS
Copy link
Member

Hi @lindexi

Thank you for the insights you have provided. However, when I tried to reproduce the issue, it seems the increase in memory is due to the oldBorder element retention at line #38.

Please share more information such as memory dump taken at different intervals which shows the memory increase (after commenting out the aforementioned line 38).

This will help us repro the issue at our end and will help us narrow down the problem.

@pchaurasia14 pchaurasia14 added the 📭 waiting-author-feedback To request more information from author. label Oct 10, 2022
@lindexi
Copy link
Member Author

lindexi commented Oct 11, 2022

@Kuldeep-MS Thank you.

The increase in memory is due to the oldBorder element retention

Right. We must keep the Image control alive, and we should remove the current Image control from the visual tree. The Borders.Add(oldBorder) will add the reference of oldBorder. And the oldBorder references Image control.

But the Image control still reference the RenderTargetBitmap after we set the souce to null by oldImage.Source = null

In other words, the Image control not being recycled is as expected. But the RenderTargetBitmap not being recycled is not as expected.

It means that the RenderTargetBitmap can not be deleted from memory.


And I think we can fix this by #7177

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Product bug (most likely) .NET Framework Performance Performance related issue
Projects
Status: Todo
Development

No branches or pull requests

7 participants