Pergunta

Apesar de eu entender as graves implicações de jogar com esta função (ou pelo menos é o que eu acho), não vejo por que ele está se tornando uma dessas coisas que os programadores respeitáveis ??não iria nunca usam, mesmo aqueles que don' t sequer sabem o que é para.

Vamos dizer que eu estou desenvolvendo uma aplicação onde o uso de memória varia muito dependendo do que o usuário está fazendo. O ciclo de vida do aplicativo pode ser dividida em duas fases principais: a edição e processamento em tempo real. Durante a fase de edição, suponha que bilhões ou mesmo trilhões de objetos são criados; alguns deles pequenos e alguns deles não, alguns podem ter finalizadores e alguns não pode, e suponha que suas vidas variar de alguns poucos milissegundos para longas horas. Em seguida, o usuário decide mudar para o estágio em tempo real. Neste ponto, vamos supor que o desempenho desempenha um papel fundamental e a menor alteração no fluxo do programa poderia trazer consequências catastróficas. criação do objeto é então reduzido ao mínimo possível usando pools de objeto e os tais, mas, em seguida, os sinos GC em inesperadamente e joga tudo fora, e alguém morre.

A pergunta:? Neste caso, não seria sábio para chamar GC.Collect () antes de entrar na segunda etapa

Afinal, essas duas etapas não se sobrepõem no tempo uns com os outros e todas as estatísticas de otimização eo GC poderia ter reunido seria de pouca utilidade aqui ...

Nota: Como alguns de vocês têm apontado, .NET pode não ser a melhor plataforma para um pedido como este, mas isso está além do escopo desta questão. A intenção é esclarecer se uma chamada GC.Collect () pode melhorar de uma aplicação geral de comportamento / desempenho ou não. Nós todos concordamos que as circunstâncias em que você faria uma coisa dessas são extremamente raros, mas, novamente, o GC tenta adivinhar e faz isso muito bem a maior parte do tempo, mas ainda é cerca de adivinhação.

Graças.

Foi útil?

Solução

do blog de Rico ...

Regra # 1

Do not.

Este é realmente o mais importante regra. É justo dizer que a maioria usos de GC.Collect () são uma má idéia e eu entrei em que em algum detalhe em a postagem original por isso não vou repetir tudo o que aqui. Então, vamos passar para ...

Regra nº 2

Considere chamando GC.Collect () se algum não recorrentes evento que acabou de acontecer e este evento é altamente provável que ter causado um monte de objetos antigos para die.

Um exemplo clássico disso é se você estiver escrever um aplicativo cliente e você exibir um muito grande e complicado formulário que tem um monte de dados associados com isso. Seu usuário tem apenas interagiu com esta forma potencialmente criação de alguns objetos grandes ... coisas como documentos XML, ou um grande DataSet ou dois. Quando a forma fecha estes objetos estão mortos e assim GC.Collect () irá recuperar a memória associada com eles ...

Então parece que esta situação pode cair sob a Regra nº 2, você sabe que há um momento no tempo em que uma grande quantidade de objetos antigos morreram, e é não-recorrente. No entanto, não se esqueça as palavras de despedida de Rico.

Rule # 1 deve governar trunfo # 2 sem forte evidência.

Medida, medida, medida.

Outras dicas

Se você chamar GC.Collect () no código de produção que são essencialmente declarando que você sabe mais do que os autores do GC. Talvez seja o caso. No entanto, geralmente, não é, e, portanto, fortemente desencorajada.

Assim como sobre quando você estiver usando objetos COM como o MS Word ou MS Excel a partir do .NET? Sem pôr GC.Collect após a liberação do COM objetos, descobrimos que as instâncias de aplicativos Word ou Excel ainda existem.

Na verdade, o uso que código é:

Utils.ReleaseCOMObject(objExcel)

' Call the Garbage Collector twice. The GC needs to be called twice in order to get the
' Finalizers called - the first time in, it simply makes a list of what is to be finalized,
' the second time in, it actually does the finalizing. Only then will the object do its 
' automatic ReleaseComObject. Note: Calling the GC is a time-consuming process, 
' but one that may be necessary when automating Excel because it is the only way to 
' release all the Excel COM objects referenced indirectly.
' Ref: http://www.informit.com/articles/article.aspx?p=1346865&seqNum=5
' Ref: http://support.microsoft.com/default.aspx?scid=KB;EN-US;q317109
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()

Então, isso seria um uso incorrecto do coletor de lixo? Se sim, como é que vamos chegar a Interop objetos para morrer? Além disso, se não é para ser usado como este, porque é o método GC mesmo Collect do Public?

Bem, a GC é uma daquelas coisas que eu tenho uma relação de amor / ódio com. Temos quebrado na passado através de VistaDB e blog sobre isso. Eles fixaram-lo, mas é preciso um longo tempo para obter correções de-los em coisas como esta.

O GC é complexo, e um tamanho único abordagem é muito, muito difícil de tirar algo deste grande. MS tem feito um bom trabalho dele, mas é possível enganar o GC às vezes.

Em geral, você não deve adicionar um Collect se você não sabe para um fato que acabou despejado uma tonelada de memória e ele irá para a mid vida crise se o GC não obtê-lo limpo até agora.

Você pode estragar toda a máquina com uma série de declarações GC.Collect ruins. A necessidade de uma declaração a cobrar quase sempre aponta para um erro subjacente maior. O vazamento de memória geralmente tem a ver com as referências e uma falta de compreensão de como eles funcionam. Ou usar da IDisposable em objetos que não precisam dele e colocar uma carga muito maior no GC.

Watch perto a% de tempo gasto no GC através dos contadores de desempenho do sistema. Se você ver seu aplicativo usando 20% ou mais do seu tempo no GC você tem problemas de gerenciamento de objetos graves (ou um padrão de uso anormal). Você quer minimizar sempre o tempo que o GC passa, porque ele vai acelerar o seu aplicativo inteiro.

Também é importante notar que a GC é diferente em servidores que estações de trabalho. Eu vi um número de pequenas difícil de rastrear problemas com as pessoas não testar os dois (ou nem mesmo ciente de que os seus são dois deles).

E só para ser o mais completo na minha resposta quanto possível, você também deve testar sob Mono se você está direcionando essa plataforma também. Uma vez que é uma implementação totalmente diferente pode experimentar totalmente diferentes problemas que a implementação MS.

Existem situações em que é útil, mas em geral ele deve ser evitado. Você pode compará-lo com GOTO, ou andar de ciclomotor:. Fazê-lo quando você precisa, mas você não contar a seus amigos sobre isso

De minha experiência, nunca foi aconselhável fazer uma chamada para GC.Collect () no código de produção. Na depuração, sim, ele tem as suas vantagens para ajudar a esclarecer vazamentos de memória em potencial. Acho que a minha razão fundamental é que a GC tem sido escrito e otimizado por programadores muito mais inteligente, então eu, e se eu chegar a um ponto que eu sinto que eu preciso chamar GC.Collect () é um indício de que eu ter ido caminho algum lugar. Em sua situação não soa como você realmente tem problemas de memória, só que você está preocupado que a instabilidade da coleção vai trazer para o seu processo. Vendo que ele não vai limpar objetos ainda em uso, e que se adapta muito rapidamente para ambos subindo e baixando demandas, eu acho que você não terá que se preocupar com isso.

Uma das maiores razões para chamar GC.Collect () é quando você acabou de realizar um evento significativo que cria lotes de lixo, como o que você descreve. Chamando GC.Collect () pode ser uma boa idéia aqui; caso contrário, o GC pode não entender que era um evento 'uma vez'.

É claro, você deve perfil dele, e veja por si mesmo.

Bem, obviamente você deve código não escrita com requisitos de tempo real em línguas com a coleta de lixo em tempo não-real.

Em um caso com etapas bem definidas, não há nenhum problema com acionando o coletor de lixo. Mas neste caso é extremamente raro. O problema é que muitos desenvolvedores estão indo para tentar usar isso para papel-over problemas em um estilo de carga e de culto, e adicioná-lo indiscriminadamente vai causar problemas de desempenho.

Chamando GC.Collect () força o CLR para fazer um passeio de pilha para ver se cada objeto pode ser verdadeiramente ser lançado pela verificação de referências. Isso vai afetar a escalabilidade se o número de objetos é alta, e também tem sido conhecida a coleta de lixo gatilho muitas vezes. Confie no CLR e deixar que o próprio prazo coletor de lixo quando for o caso.

A criação de imagens em um loop - mesmo se você chamar Dispose, a memória não é recuperada. Coleta de lixo de cada vez. Eu fui de memória 1.7GB no meu aplicativo de processamento de fotos para 24MB e desempenho é excelente.

Não há absolutamente tempo que você precisa para chamar GC.Collect.

De fato, eu não acho que isso é uma prática muito ruim para chamar GC.Collect.
Pode haver casos em que precisamos disso. Apenas por exemplo, eu tenho um formulário que corre um fio, que inturn abre tabelas differnt em um banco de dados, extrai o conteúdo em um campo BLOB para um arquivo temporário, criptografar o arquivo, em seguida, ler o arquivo em um binarystream e para trás em um BLOB campo em outra tabela.

Toda a operação leva um monte de memória, e não é certo sobre o número de linhas e tamanho do conteúdo do arquivo nas tabelas.
Eu costumava ficar Exceção OutofMemory muitas vezes e eu pensei que seria sábio para GC.Collect periodicamente executado com base em uma variável de contador. I incrementar um contador e quando um nível especificado for atingido, GC é chamado para recolher qualquer lixo que pode ter formado, e para recuperar qualquer memória perdida devido a vazamentos de memória imprevistas.

Depois disso, eu acho que está funcionando bem, pelo menos não é exceção !!!
Eu chamo da seguinte maneira:

var obj = /* object utilizing the memory, in my case Form itself */
GC.Collect(GC.GetGeneration(obj ,GCCollectionMode.Optimized).

Sob .NET, o tempo necessário para realizar uma coleta de lixo é muito mais fortemente relacionado com a quantidade de coisas que não é lixo, do que a quantidade de material que é. Na verdade, a menos que Finalize um objeto substitui (ou explicitamente, ou via C # destructor), é o alvo de um WeakReference, senta no Large Object Heap, ou é especial de alguma outra forma gc-relacionada, a única coisa que identifica a memória em que ele fica como sendo um objecto é a existência de referências a ele enraizadas. Caso contrário, a operação do GC é análogo a tomar a partir de um tudo construção de valor e dinamitar o edifício, a construção de um novo no local do antigo, e colocar todos os itens valiosos nele. O esforço necessário para dinamitar o edifício é totalmente independente da quantidade de lixo dentro dela.

Por isso, chamando GC.Collect é capaz de aumentar a quantidade total de trabalho o sistema tem que fazer. Ele vai retardar a ocorrência da próxima coleção, mas provavelmente vai fazer tanto trabalho imediatamente como a próxima coleção teria exigido quando ocorreu; no momento em que a próxima coleção teria ocorrido, a quantidade total de tempo gasto na coleta terá sido aproximadamente o mesmo que GC.Collect não tinha sido chamado, mas o sistema terá acumulado algum lixo, fazendo com que a coleção sucedendo a ser exigido mais cedo do que tinha não GC.Collect sido chamado.

As vezes eu posso ver GC.Collect realmente ser útil é quando, necessita-se medir o uso de memória de algum código (desde figuras uso de memória só são realmente significativa após uma coleção), ou perfil que de vários algoritmos é melhor (GC chamando .Recolher () antes de executar cada uma das várias peças de código pode ajudar a garantir um estado de linha de base consistente). Existem alguns outros casos em que se pode conhecer as coisas do GC não, mas a menos que se está escrevendo um programa single-threaded, não há nenhuma maneira se pode saber que uma chamada GC.Collect que iria ajudá-estruturas de dados de um segmento evitar a "mid-life crise" não causaria dados de outros segmentos para ter uma 'crise de meia-idade', que de outra forma teriam sido evitados.

Nós tivemos um problema semelhante com o coletor de lixo não coleta de lixo e liberando memória.

Em nosso programa, estávamos processando algumas planilhas de tamanho modesto do Excel com OpenXML. As planilhas contidas em qualquer lugar de 5 a 10 "folhas" com cerca de 1000 linhas de 14 colunas.

O programa em um ambiente de 32 bits (x86) deixaria de funcionar com uma "falta de memória" de erro. O hotel disse que ele seja executado em um ambiente x64, mas queríamos uma solução melhor.

Nós encontramos um.

Aqui estão alguns fragmentos de código simplificado do que não funcionou eo que não funcionou quando se trata de chamar explicitamente o coletor de lixo para liberar memória de objetos descartados.

Chamando o GC de dentro da sub-rotina não funcionou. Memória nunca foi recuperado ...

For Each Sheet in Spreadsheets
    ProcessSheet(FileName,sheet)
Next

Private Sub ProcessSheet(ByVal Filename as string, ByVal Sheet as string)
    ' open the spreadsheet 
    Using SLDoc as SLDocument = New SLDocument(Filename, Sheet)
        ' do some work....
        SLDoc.Save
    End Using
    GC.Collect()
    GC.WaitForPendingFinalizers()
    GC.Collect()
    GC.WaitForPendingFinalizers()
End Sub

Ao mover a chamada GC para fora do âmbito da sub-rotina, o lixo foi recolhido e a memória foi liberado.

For Each Sheet in Spreadsheets
    ProcessSheet(FileName,sheet)
    GC.Collect()
    GC.WaitForPendingFinalizers()
    GC.Collect()
    GC.WaitForPendingFinalizers()
Next

Private Sub ProcessSheet(ByVal Filename as string, ByVal Sheet as string)
    ' open the spreadsheet 
    Using SLDoc as SLDocument = New SLDocument(Filename, Sheet)
        ' do some work....
        SLDoc.Save
    End Using
End Sub

Espero que isso ajude outros que estão frustrados com a coleta de lixo .NET quando parece ignorar as chamadas para GC.Collect().

Paul Smith

Nada está errado com explicitamente chamando para uma coleção. Algumas pessoas apenas realmente quero acreditar que se é um serviço prestado pelo fornecedor, não questioná-la. Ah, e todos esses congelamentos nos momentos errados de seu aplicativo interativo? A próxima versão vai torná-lo melhor!

Deixando um negócio processo de fundo com meios de manipulação de memória não ter que lidar com isso nós mesmos, é verdade. Mas isso não logicamente significa que é melhor para nós não lidar com isso nós mesmos em todas as circunstâncias. A CG é optimizado para a maioria dos casos. Mas isso não logicamente significa que ele é otimizado em todos os casos.

Você já respondeu uma questão em aberto, tais como 'qual é o melhor algoritmo de classificação' com uma resposta definitiva? Se assim for, não toque no GC. Para aqueles de vocês que pediu para as condições, ou deram 'neste caso' respostas de tipo, você pode continuar a aprender sobre o GC e quando para ativá-lo.

congela aplicação Tenho que dizer, que eu tive no Chrome e Firefox que frustrar o inferno fora de mim, e mesmo assim em alguns casos a memória cresce sem obstáculos - Se ao menos eles tivessem aprender a chamar o coletor de lixo - ou me deu um botão para que, como eu começo a ler o texto de uma página que posso batê-lo e, assim, ser livre de geadas para os próximos 20 minutos.

Eu acho que você está certo sobre o cenário, mas não tenho certeza sobre a API.

A Microsoft diz que, em tais casos, você deve pressionar memória add como uma dica para o GC que em breve deverá executar uma coleção.

O que há de errado com ele? O fato de que você está tentando adivinhar o coletor de lixo e alocador de memória, que entre eles têm uma maior ideia muito sobre uso de memória real do seu aplicativo em tempo de execução do que você.

O desejo de chamar GC.Collect () geralmente está tentando encobrir os erros que você fez em outro lugar!

Seria melhor se você encontrar onde você se esqueceu de descartar coisas que você não precisa mais.

A linha inferior, você pode traçar o perfil do aplicativo e ver como essas coleções adicionais afetar as coisas. Eu sugiro ficar longe dele, embora a menos que você está indo para o perfil. O GC é projetado para cuidar de si mesmo e com a evolução do tempo de execução, eles podem aumentar a eficiência. Você não quer um monte de enforcamento código em torno que podem estragar as obras e não ser capaz de tirar proveito dessas melhorias. Há um argumento semelhante para usar foreach em vez de para, o que foi, que futuras melhorias debaixo das cobertas pode ser adicionado a foreach e seu código não tem que mudar para tirar proveito.

O .NET Framework em si nunca foi concebido para ser executado em um ambiente em tempo real. Se você realmente precisa realtime processamento você quer usar uma linguagem em tempo real incorporado que não é baseado em .NET ou usar o .NET Compact Framework em execução em um dispositivo Windows CE.

O pior que vai fazer é fazer o seu congelamento programa um pouco. Então, se isso é OK com você, fazê-lo. Normalmente não é necessário para grossas cliente ou web apps com a maioria interação do usuário.

Eu descobri que às vezes programas com tópicos de longa duração, ou programas de lote, terá exceção OutOfMemory embora sejam descartar objetos corretamente. Uma que me lembro foi um processamento de transações de banco de dados de linha de negócios; o outro era uma rotina de indexação em uma discussão de fundo em um aplicativo cliente de espessura.

Em ambos os casos, o resultado era simples: Não GC.Collect, falta de memória, de forma consistente; GC.Collect, desempenho impecável.

Eu tentei-lo para resolver problemas de memória várias outras vezes, sem sucesso. Eu o tirei.

Em suma, não colocá-lo em menos que você está recebendo erros. Se você colocá-lo em e não resolver o problema de memória, leve de volta para fora. Lembre-se de teste no modo de versão e comparar maçãs com maçãs.

A única vez que as coisas podem dar errado com isso é quando você começa moralista sobre isso. Não é uma questão de valores; muitos programadores tenham morrido e ido direto para o céu com muitas GC.Collects desnecessárias em seu código, o que lhes sobrevive.

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