Вопрос

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

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

Как я могу освободить объекты при их удалении из коллекции Children на холсте?

<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");
  }
}

Нет правильного решения

Другие советы

Изменять

public class MyControl : UserControl

к

public class MyControl : ContentControl

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

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

Также см этот:

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

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

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

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

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

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

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

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


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

this.UpdateLayout();

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

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

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

Возможно, вам это будет интересно.Недавно я узнал, что расширение разметки x:Name хранит ссылку на UIElement в родительском элементе управления в словаре, связанном с именем строки.

Когда вы удаляете UIElement из его родителя, словарь сохраняет ссылку на элемент управления.

Здесь есть сообщение в блоге/видео об отладке утечки памяти: WPF X: утечка памяти имени

Решение состоит в том, чтобы не использовать x:Name или обеспечить удаление элементов управления, которые поддерживаются x:Name, чтобы не занимать слишком много памяти перед сбором раздела визуального дерева.

Обновлять: Вы отменяете регистрацию именованного класса, используя Область имен

this.grid.Children.Remove(child); // Remove the child from visual tree
NameScope.GetNameScope(this).UnregisterName("child"); // remove the keyed name
this.child = null; // null the field

// Finally it is free to be collected! 

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top