Я читал об обработке памяти WPF и следил за каждым 5-ю и 8-ю ловушками утечки памяти, но ничто не помогает мне в моей текущей ситуации.
У меня была проблема с моим программным обеспечением, где WPF не освободит память до тех пор, пока программа не завершится. Если я позволю этому go навсегда, это вызовет исключение OutOfMemoryException, независимо от того, что я делаю. Мне удалось выделить проблему в небольшом примере, чтобы показать, как она не освобождает свою память, хотя я ее больше не использую. Вот как я могу воспроизвести проблему:
Я создал 2 проекта, одну консольную программу и одно приложение WPF. В моем приложении WPF у меня есть MainWindow.xaml, в котором ничего нет:
<Window x:Class="MemoryLeakWpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MemoryLeakWpfApp"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800" Loaded="MainWindow_OnLoaded">
<Grid>
</Grid>
</Window>
Я подписываюсь на событие Loaded, которое использую для мгновенного закрытия окна, которое можно увидеть в файле .cs здесь. :
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Debug.WriteLine("Constructing",GetType().Name);
}
~MainWindow()
{
Debug.WriteLine("Deconstructing", GetType().Name);
}
private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
Close();
}
}
Я также добавил строки отладки в свой конструктор и деконструктор, чтобы я мог отслеживать, когда он создается и удаляется. Затем я создаю класс Controller в приложении WPF, который представляет точку входа в эту библиотеку классов WPF, в которой есть метод для создания и отображения окна:
public class Controller
{
public void Execute()
{
MainWindow window = new MainWindow();
window.ShowDialog();
Debug.WriteLine("Constructing", GetType().Name);
}
~Controller()
{
Debug.WriteLine("Deconstructing", GetType().Name);
}
}
Здесь я также добавил строки дорожки отладки. У меня нет App.xaml, так как этот проект WPF настроен как библиотека классов в своих свойствах. Это часть WPF. В консольном проекте я добавил следующий код в свой основной класс:
[STAThread]
static void Main(string[] args)
{
for (int i = 0; i < 100; i++)
{
Controller controller = new Controller();
Console.WriteLine("Test " + i);
controller.Execute();
}
Console.WriteLine("Pressing enter will close this");
Console.ReadLine();
Debug.WriteLine("Party is over, lets leave");
}
Итак, в основном, у меня есть консольный класс, который хочет показать диалог. Он создает контроллер для приложения WPF и вызывает Execute. Контроллер показывает окно, которое сразу же закрывается после завершения загрузки. Затем класс консоли создает новый контроллер для повторного выполнения процесса. Вот что я вижу в своем выводе:
MainWindow: Constructing
Controller: Constructing
MainWindow: Constructing
Controller: Constructing
Controller: Deconstructing
MainWindow: Constructing
Controller: Constructing
Controller: Deconstructing
MainWindow: Constructing
Controller: Constructing
Controller: Deconstructing
MainWindow: Constructing
Controller: Constructing
Controller: Deconstructing
Контроллер строит и деконструирует, а окно - нет. Однако, когда for l oop завершено, и я нажимаю Enter, чтобы позволить программе завершиться, я получаю это:
Party is over, lets leave
MainWindow: Deconstructing
Controller: Deconstructing
MainWindow: Deconstructing
Controller: Deconstructing
MainWindow: Deconstructing
MainWindow: Deconstructing
MainWindow: Deconstructing
MainWindow: Deconstructing
MainWindow: Deconstructing
MainWindow: Deconstructing
MainWindow: Deconstructing
MainWindow: Deconstructing
MainWindow: Deconstructing
MainWindow: Deconstructing
MainWindow: Deconstructing
Внезапно все экземпляры MainWindow теперь деконструируются, но только когда Программа заканчивается, а не когда мы отбрасываем ссылку в for l oop. Это означает, что в нашей программе у нас есть только конечное число раз, когда мы можем открыть окно до возникновения исключения OutOfMemoryException.
Но вопрос на миллион с половиной долларов: Как я могу убедить WPF освободить память во время работы программы, а не при ее закрытии?