Pergunta

Estou trabalhando em um projeto em larga escala, onde uma estrutura personalizada (muito boa e robusta) foi fornecida e temos que usá -lo para exibir formas e visualizações.


Existe a Classe Straticizadora de classe abstrata (derivada de alguma classe na estrutura) que é instanciada sempre que uma nova forma de estratégia é aberta.

StrategyForm (um quadro de janela personalizado) contém StrategyEditor.
StrategyEditor contém StrategyTab.
StrategyTab contém StrategyCanvas.

Esta é uma pequena parte das grandes classes para esclarecer que existem muitos objetos que serão criados se um objeto Strategyform for alocado na memória no tempo de execução. Meu componente possui todas essas classes mencionadas acima, exceto StrategyForm cujo código não está sob meu controle.


Agora, em tempo de execução, o usuário abre muitos objetos de estratégia (que acionam a criação de um novo objeto Strategform.) Depois de criar aprox. 44 Objetos de estratégia, vemos que o objeto do usuário manipula (usarei o UOH daqui em diante) criado pelo aplicativo atinge cerca de 20k+, enquanto no registro o valor padrão das alças é 10K. Leia mais sobre os objetos do usuário aqui. O teste em diferentes máquinas deixou claro que o número de objetos de estratégia abertos é diferente para a mensagem para aparecer - em um M/C se tiver 44, pode ser 40 em outro.

Quando vemos a mensagem pop-up, isso significa que o aplicativo responderá lentamente. Piora com mais alguns objetos e, em seguida, a criação de quadros de janela e objetos subsequentes falham.

Primeiro, pensamos que não era uma questão de memória. Mas então lendo mais sobre new em C# Ajudou a entender que uma exceção seria lançada se o aplicativo acabasse sem memória. Este não é um problema de memória, então, eu acho que (o gerenciador de tarefas também mostrou 1,5 GB de memória disponível.)


Especificações m/c
Núcleo 2 duo 2GHz+
4 GB de RAM
80 GB+ espaço de disco livre para arquivo de página
Conjunto de memória virtual: 4000 - 6000


Minhas perguntas


Q1. Isso parece um problema de memória e estou errado que não seja?
Q2. Isso ponto para a exaustão de UOHs gratuitos (como estou pensando) e que resultando na falha da criação de alças de janelas?
Q3. Como podemos evitar carregar um StrategyEditor Objeto (além de um limiar, ficando de olho no uso atual do UOHS)? (Já sabemos como buscar o número de UOHs em uso, então não vá para lá.) Lembre -se de que o chamado para new StrategyForm() está fora do controle do meu componente.
Q4. Estou um pouco confuso - o que são Lida com objetos de usuário exatamente? O MSDN está falando sobre qualquer objeto que criamos ou apenas alguns objetos específicos, como alças de janela, alças do cursor, alças de ícone?
Q5. O que exatamente faz com que use um UOH? (quase o mesmo que Q4)

Eu ficaria muito grato a quem pode me dar algumas respostas experientes. Muito obrigado! :)

Atualizar
Com base na resposta STAKX, observe que as janelas que estão sendo abertas serão fechadas apenas pelo usuário. Esta é a espécie de situação do aplicativo MDI, onde muitas crianças são abertas. Então, Dispose Não pode ser chamado sempre que queremos.

Foi útil?

Solução

Q1

Parece que você está tentando criar muitos controles de interface do usuário ao mesmo tempo. Mesmo que restem a memória, você está ficando sem alças. Veja abaixo uma explicação breve, mas bastante técnica.

Q4

Eu entendo um objeto de usuário ser qualquer objeto que faça parte da GUI. Pelo menos até o Windows XP, a API da interface do Windows residiu em USER.DLL (uma das principais DLLs que compõem o Windows). Basicamente, a interface do usuário é composta de "Windows". Todos os controles, como botões, caixas de texto, caixas de seleção, são internamente a mesma coisa, a saber, "Windows". Para criá -los, você chamaria a função da API Win32 CreateWindow. Essa função retornaria um identificador à "janela" criada (elemento da interface do usuário ou "objeto de usuário").

Então eu presumo que um identificador de objeto do usuário é uma alça conforme retornado por esta função. (WinForms é baseado na antiga API Win32 e, portanto, usaria o CreateWindow função.)

Q2

Na verdade, você não pode criar tantos controles da interface do usuário quanto quiser. Todas essas alças recuperadas através CreateWindow em algum momento deve ser libertado. Em Winforms, a maneira mais fácil e segura de fazer isso é através do uso do using Bloco ou ligando Dispose:

using (MyForm form = new MyForm())
{
    if (form.ShowDialog() == DialogResult.OK) ...
}    

Basicamente, tudo System.Windows.Forms.Control pode ser Disposed, e deve ser descartado. Às vezes, isso é feito para você automaticamente, mas você não deve confiar nisso. Sempre Dispose Sua interface do usuário controla quando você não precisa mais deles.

Nota em Dispose Para formulários modais e modificados:

  • Formas modais (mostradas com ShowDialog) são não descartado automaticamente. Você precisa fazer isso sozinho, como demonstrado no exemplo de código acima.
  • Formas modificadas (mostradas com Show) são descartados automaticamente para você, pois você não tem controle sobre quando será fechado pelo usuário. Não há necessidade de ligar explicitamente Dispose!

Q5

Toda vez que você cria um objeto de interface do usuário, o WinForms faz chamadas internamente para CreateWindow. É assim que as alças são alocadas. E eles não são libertados até uma chamada correspondente para DestroyWindow é feito. Nas formas de win, essa chamada é desencadeada através do Dispose método de qualquer System.Windows.Forms.Control. (Nota: Embora eu esteja bem certo sobre isso, estou realmente adivinhando um pouco. Posso não estar 100% correto. Dando uma olhada nos internos do Winforms usando o refletor, revelaria a verdade.)

Q3

Assumindo que você StrategyEditor Cria um enorme grupo de controles da interface do usuário, acho que você não pode fazer muito. Se você não pode simplificar esse controle (com relação ao número de controles infantis que ele cria), parece que você está preso na situação em que está. Você simplesmente não pode Crie infinitamente muitos controles da interface do usuário.

Você poderia, no entanto, acompanhar quantos StrategyEditors são abertos a qualquer momento (aumente um contador sempre que se for instanciado e diminui -o sempre que se fechar - você pode rastrear o último usando o FormClosing/FormClosed evento de uma forma, ou no Dispose método de controle). Então você pode limitar o número de abertos simultaneamente StrategyEditors para um número fixo, digamos 5. Se o limite for excedido, você poderá lançar uma exceção no construtor, para que não sejam criadas mais instâncias. Claro que não posso dizer se StrategyForm vai lidar com uma exceção do seu StrategyEditor Construtor bem ...

public class StrategyEditor : ...
{
    public StrategyEditor()
    {
        InitializeComponent();

        if (numberOfLiveInstances >= maximumAllowedLiveInstances)
            throw ...;
        // not a nice solution IMHO, but if you've no other choice...
    }
}

Em ambos os casos, limitando o número de instanciados StrategyEditorS parece ser uma correção temporária para mim e não resolverá o problema real.

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