Pergunta

Atualizar: Eu tentei isso em outra máquina, mais limpa instalada. Não pude reproduzir isso nessa máquina. Se eu descobrir o que o componente ofensivo (vsstudio) causa isso, avisarei você.

Criei alguns uielements do código atrás e estava antecipando a coleção de lixo para limpar as coisas. No entanto, os objetos não são livre no momento em que eu esperava. Eu esperava que eles fossem libertados no Removeat (0), mas eles só são libertados no final do programa.

Como posso fazer com que os objetos sejam libertados quando removidos da coleção de crianças da tela?

<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>

O código por trás é:

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

Nenhuma solução correta

Outras dicas

Mudar

public class MyControl : UserControl

para

public class MyControl : ContentControl

e dirá adeus (após a segunda vez que você remove o controle.) Eu também verifiquei a memória não vazar usando

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

Veja também isto:

Você remove o testcontrol com limpeza de grade. Crianças, mas ele não é imediatamente elegível para a coleta de lixo. Várias operações assíncronas estão pendentes e não podem ser GC até que essas operações sejam concluídas (isso inclui o aumento do evento descarregado e algum código de limpeza no mecanismo de renderização).

Verifiquei que, se você esperar até que essas operações sejam concluídas (digamos, programando uma operação de despachante na prioridade do contexto), o testcontrol se tornará elegível para o GC, independentemente da presença de uma ligação no bloco de texto.

O UserControl deve ter um evento interno que não se limpe rapidamente, ou pode ser um bug com o VS2010 RC. Eu relataria isso através do Connect, mas por enquanto muda para o ContentControl.

Como você está usando o UserControl, presumo que você também precise mudar para usar o modelo genérico.xaml. Isso não é muito difícil de mudar (e para a maioria das coisas é uma solução melhor.)

Os objetos em C# não são automaticamente "liberados" assim que não são mais usados.

Pelo contrário, quando você remove o objeto do seu controle, ele se torna elegível para coleta de lixo Nesse ponto, supondo que você não tenha outras referências a esse uielement.

Depois que um objeto é "não enraizado" (não há referências, direta ou indiretamente, de qualquer objeto usado em seu aplicativo), ele se torna elegível para a coleta. O coletor de lixo, eventualmente, limpará seu objeto, mas quando isso acontecer não é algo que você (normalmente) controle.

Apenas confie que acabará sendo limpo. Essa é a beleza de C# (e .NET em geral) - a gerência e a preocupação disso são tratadas para você.


EDIT: Após alguns testes, parece que a janela contém uma referência ao UIELEMENT até o próximo passe de layout. Você pode forçar isso a ocorrer adicionando uma chamada a:

this.UpdateLayout();

Depois de remover o (s) elemento (s) das crianças da tela. Isso fará com que os objetos estejam disponíveis para o GC.

Existem três gerações de coleta de lixo em C#, portanto, mesmo que não haja referências aos seus objetos, podem levar três coleções de lixo para libertá -las.

Você pode usar o parâmetro gc.collect () para forçar uma coleção de lixo de 3ª geração,
No entanto, o melhor aprotech é não ligar para GC.Collect (),
Em vez disso, use a interface idispotável e vincule as crianças a uma observaBleCollection e quando você recebe um evento de coleta de disposição () de qualquer objetivo removido.

Você pode encontrar isso de interesse. Descobri recentemente que X: Nome Markup Extension armazena uma referência ao UIELEMENT no controle dos pais em um dicionário digitado pelo nome da string.

Quando você remove o UIELEMENT de seus pais, o dicionário mantém uma referência ao controle.

Há uma postagem de blog / vídeo depurando o vazamento de memória aqui: WPF X: Vazamento de memória de nome

A solução é não usar x: nome ou garantir que os controles que são mantidos vivos por x: nome sejam limpos para não consumir muita memória antes que uma seção da árvore visual seja coletada.

Atualizar: Você desregira uma classe nomeada usando o NamesCope

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! 

Tivemos o mesmo problema e também pensamos que esse pode ser o motivo. Mas analisamos nosso projeto usando ferramentas de perfil de memória e descobrimos que não há nada a ver com a grade.Remove ou Grid.Removeat. Então, acho que minha sugestão é apenas dar uma olhada no seu projeto na ferramenta de perfil de memória e ver o que está acontecendo dentro do seu projeto. espera que isso ajude.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top