В WPF: Дети. Удалите или Дети. Ясный не освобождает объекты

Обновление: Я попробовал это на другом, более чисто установленном, машина. Я не мог воспроизвести это на той машине. Если я узнаю то, что, нарушая (VSStudio) компонент вызывает это, то я сообщу.

Я создаю некоторый UIElements из кода позади, и ожидал сборку "мусора" для разрешения материала. Однако объекты не являются свободным редактором в то время, когда я ожидал это. Я ожидал, что они будут освобождены в RemoveAt (0), но они только освобождены в конце программы.

Как я могу заставить объекты быть освобожденными при удалении из Дочернего набора Холста?

<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300"
    MouseDown="Window_MouseDown">
  <Grid>
    <Canvas x:Name="main" />
  </Grid>
</Window>

Код позади:

public partial class MainWindow : Window
{
  public MainWindow()
  {
    InitializeComponent();
  }

private void Window_MouseDown(object sender, MouseButtonEventArgs e)
{
  GC.Collect(); // This should pick up the control removed at a previous MouseDown
  GC.WaitForPendingFinalizers(); // Doesn't help either

  if (main.Children.Count == 0)
    main.Children.Add(new MyControl() { Background = Brushes.Yellow, Width = 100, Height = 50 });
  else
    main.Children.RemoveAt(0);
 }
}

public class MyControl : UserControl
{
  ~MyControl()
  {
    Debug.WriteLine("Goodbye");
  }
}
12
задан Vadim Kotov 17 August 2017 в 14:09
поделиться

4 ответа

Измените

открытый класс MyControl: UserControl

на

открытый класс MyControl: ContentControl

, и он попрощается (после второго удаления элемента управления.) Я также проверил отсутствие утечек памяти, используя

Debug.WriteLine ("mem:" + GC.GetTotalMemory (true) .ToString ());

Также см. this :

Вы удаляете TestControl, очищая grid.Children, но он не сразу подходит для сборки мусора. Несколько асинхронных операций с ним ожидают выполнения, и сборщик мусора не может быть завершен до тех пор, пока эти операции не будут завершены (к ним относятся создание события Unloaded и некоторого кода очистки в механизме рендеринга).

Я проверил, что если вы дождетесь завершения этих операций (скажем, запланировав операцию Dispatcher с приоритетом ContextIdle), TestControl станет подходящим для GC, независимо от наличия привязки к TextBlock.

UserControl должен либо иметь внутреннее событие, которое не очищается быстро, либо это может быть ошибка VS2010 RC. Я бы сообщил об этом через connect, а пока переключился на ContentControl.

Поскольку вы используете UserControl, я предполагаю, что вам также придется переключиться на использование шаблона Generic.xaml. Это не так уж сложно (и для большинства вещей это лучшее решение).

8
ответ дан 2 December 2019 в 19:53
поделиться

Объекты в C # не освобождаются автоматически, как только они больше не используются.

Скорее, когда вы удаляете объект из своего Control, он становится подходящим для сборки мусора в этот момент, если у вас нет других ссылок на этот UIelement.

После того, как объект «не рутирован» (нет прямых или косвенных ссылок на какой-либо используемый объект в вашем приложении), он становится пригодным для сбора. Затем сборщик мусора в конечном итоге очистит ваш объект, но когда это происходит, вы (обычно) не контролируете.

Просто верьте, что со временем он будет очищен. В этом прелесть C # (и .NET в целом) - управление этим и забота о нем ложатся на вас.


Правка: после некоторого тестирования выяснилось, что окно содержит ссылку на UIelement до следующего прохода макета. Вы можете заставить это произойти, добавив вызов к:

this.UpdateLayout();

После удаления элемента (ов) с холста Children. Это сделает объекты доступными для сборки мусора.

3
ответ дан 2 December 2019 в 19:53
поделиться

У нас была та же проблема, и мы тоже думали, что это может быть причиной. Но мы проанализировали наш проект с помощью инструментов профилирования памяти и обнаружили, что тут нет ничего общего с Grid.Remove или Grid.RemoveAt. Поэтому я думаю, что я предлагаю просто взглянуть на ваш проект в инструменте профилирования памяти и посмотреть, что происходит внутри вашего проекта. надеется, что это поможет.

0
ответ дан 2 December 2019 в 19:53
поделиться

В C # существует 3 поколения сборки мусора, поэтому даже если на ваши объекты нет ссылок, для их освобождения может потребоваться 3 сборки мусора.

Вы можете использовать параметр GC.Collect () для принудительной сборки мусора 3-го поколения,
однако лучший способ - не вызывать GC.Collect () самостоятельно,
вместо этого используйте интерфейс IDisposable и привяжите дочерние элементы к ObservableCollection , а когда вы получите событие Dispose () CollectionChanged для любых удаленных объектов.

3
ответ дан 2 December 2019 в 19:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: