Memory leak. Class with finalizer

Igor Buchelnikov 1 Reputation point
2020-06-15T10:00:47.693+00:00

Created a minimal reproducing application.

Reproducing conditions:

  1. Visual Studio 2017
  2. WPF application
  3. Launch the application under the debugger
  4. WPF window code (class with finalizer, very busy WPF main thread):

code:

using System.Windows;

namespace ReproduceFinalizerMemoryLeak
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            do
            {
                Item item = new Item();
            } while (true);

            InitializeComponent();
        }
    }

    public class Item
    {
        private byte[] _bytes;

        public Item()
        {
            _bytes = new byte[10000];
        }

        ~Item()
        {

        }
    }
}

What comes up:
This application crashes with OutOfMemoryException. Item class finalizer is not called. Instances of Item class are not unloaded from memory and stays in f-reachable queue.

In my real WPF application, a memory leak occurs without debugging and under other conditions, but the manifestations are the same: finalizers are not called, memory leaks. See details and memory profiling screenshots here.

There are no problems with garbage collection if

  • I run code above in console application
  • or I run code above with class without finalizer (in my real WPF application or sample application)

It seems that under certain conditions WPF main thread blocks the thread in which finalizers are called.

Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,710 questions
{count} votes

1 answer

Sort by: Most helpful
  1. Ken Tucker 5,846 Reputation points
    2020-06-15T11:49:14.1+00:00

    Not sure how your form will ever load with a constructor like that. You need to allow the system a chance to do some house keeping. Adding an await Task.Delay should allow the garbage collector to run

        public MainWindow()
        {
            do
            {
                Item item = new Item();
                Task.Run(async () => { await Task.Delay(10); });
                Task.WaitAll();
            } while (true);
    
            InitializeComponent();
        }