Pergunta

No meu aplicativo, tenho muitas caixas de richtext que são criadas dinamicamente no tempo de execução. Percebi que o aplicativo tem um vazamento de memória, causado pelos controles RichTextBox. Para provar que a memória vazar devido ao controle, escrevi o seguinte método de teste:

for (int i = 0; i < 3000; i++)
        {
            Control rich = new RichTextBox();
            pnl.Content = rich;
        }
GC.Collect();
GC.WaitForPendingFinalizers();

pnl é um contentControl declarado no código XAML.
Se você executar o código a seguir, poderá ver que o uso da memória está crescendo rapidamente.

Alguma idéia de como resolver o problema? Eu pensei em criar um pool de objetos, mas isso complicaria meu aplicativo e prefiro evitá -lo.


editar: Adicionei uma chamada ao coletor de lixo para demonstrar que os objetos não são coletados de lixo - não há melhorias no uso da memória com e sem a chamada para o método de coleta do GC. Observe essa chamada rich.Dispose Dentro do loop elimina o crescimento do uso da memória.

Foi útil?

Solução

Encontrei isso em outros lugares, e parece estar correto no que diz respeito aos meus testes.

Quando um documento de fluxo é criado, os objetos de contexto de formatação relativamente caros também são criados para ele em seu StructuralCache. Quando você cria vários flowDocs em um loop apertado, um StructuralCache é criado para cada FlowDoc. Vamos ligar para GC.Collect no final do loop, na esperança de recuperar alguma memória. O StructuralCache possui um finalizador libera esse contexto de formatação, mas não imediatamente. O Finalizador agenda efetivamente uma operação para liberar contextos no DispatcherPriority.background.

Portanto, o RichTextBox (ou o FlowDocument), caso não esteja vazando apenas esperando um thread de segundo plano para limpar. Quando corre exatamente quem sabe. Desejo que isso acabou de implementar um método de descarte que forçaria uma limpeza imediatamente.

Outras dicas

Isso não é uma indicação de que seu aplicativo tem um vazamento de memória, é uma indicação de que seu aplicativo está Usando muita memória. É um vazamento se o RichTextBox Os controles não são liberados em algum momento depois de cair do escopo (a detecção de vazamentos de memória em objetos gerenciados é notoriamente difícil e não provável).

Um equívoco comum de que um objeto cai do escopo fará com que seja coletado de lixo. Isso só faz isso elegível a ser coletado. O objeto pode teoricamente Nunca ser coletado até que o aplicativo termine. O fato de crescer com RichTextBox E não com outros controles não é uma indicação de que existe um vazamento de memória no RichTextBox, é apenas uma indicação de que ele usa mais memória por instância do que outros controles. Embora essas informações possam ser úteis, não ajuda ao determinar se há ou não um vazamento de memória.

Tivemos o mesmo problema no WinForms 2.0 e tivemos que comprar um controle de texto rico em terceiros. Eu acho que a Microsoft não se deu ao trabalho de consertar ...

Isso corrigiu o problema para mim:http://blingcode.blogspot.com/2010/10/memory-leak-with-wpfs-richtextbox.html

Basicamente, adicione dois atributos a cada RichTextBox :) :) isundoenabled = "false"

Sobre sua edição:

Você adicionou as chamadas do GC depois o loop termina e todos os 3000 RichTextBoxES foram criados.

Embora eu concorde que parece estranho que o anterior não seja libertado dentro do loop quando é substituído por um novo, é um loop tão apertado que o GC provavelmente não está tendo a chance de "fazer as coisas" antes do loop termina.

Eu não acho que seja uma boa ideia (mas deve estar bem no código de teste), mas você já tentou mover as chamadas do GC dentro do loop?

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