O que há de tão errado em usar GC.Collect ()?

103

Embora eu entenda as sérias implicações de brincar com essa função (ou pelo menos é o que eu acho), não consigo ver por que ela está se tornando uma dessas coisas que programadores respeitáveis ​​nunca usariam, mesmo aqueles que nem mesmo sabem Para que isso serve.

Digamos que eu esteja desenvolvendo um aplicativo em que o uso de memória varia extremamente, dependendo do que o usuário está fazendo. O ciclo de vida do aplicativo pode ser dividido em dois estágios principais: edição e processamento em tempo real. Durante o estágio de edição, suponha que bilhões ou mesmo trilhões de objetos sejam criados; alguns deles pequenos e outros não, alguns podem ter finalizadores e outros não, e suponha que sua vida útil varie de poucos milissegundos a longas horas. Em seguida, o usuário decide mudar para o estágio de tempo real. Nesse ponto, suponha que o desempenho desempenhe um papel fundamental e a menor alteração no fluxo do programa pode trazer consequências catastróficas. A criação de objetos é então reduzida ao mínimo possível usando pools de objetos e tal, mas então, o GC entra inesperadamente e joga tudo fora, e alguém morre.

A pergunta: neste caso, não seria sensato chamar GC.Collect () antes de entrar no segundo estágio?

Afinal, esses dois estágios nunca se sobrepõem no tempo e todas as otimizações e estatísticas que o GC poderia ter reunido seriam de pouca utilidade aqui ...

Observação: como alguns de vocês observaram, .NET pode não ser a melhor plataforma para um aplicativo como esse, mas isso está além do escopo desta pergunta. A intenção é esclarecer se uma chamada GC.Collect () pode melhorar o comportamento / desempenho geral de um aplicativo ou não. Todos concordamos que as circunstâncias sob as quais você faria tal coisa são extremamente raras, mas, novamente, o GC tenta adivinhar e faz isso perfeitamente bem na maioria das vezes, mas ainda é sobre adivinhação.

Obrigado.

Trap
fonte
24
"a menor alteração no fluxo do programa pode trazer consequências catastróficas ... alguém pode morrer" - você tem certeza de que C # .NET é suficientemente determinista para seus objetivos?
Steve Jessop
4
Nem o Windows nem o .NET são plataformas em tempo real e, portanto, você não pode garantir métricas de desempenho, pelo menos não o suficiente a ponto de arriscar vidas humanas. Eu concordo com alguém que você está exagerando ou é descuidado.
Sergio Acosta,
3
LOL em "uma dessas coisas que programadores respeitáveis ​​nunca usariam, mesmo aqueles que nem sabem para que serve"! Programadores que usam coisas sem saber por que dificilmente são os mais respeitáveis ​​em meu livro. :)
The Dag

Respostas:

87

Do Blog de Rico ...

Regra 1

Não.

Esta é realmente a regra mais importante. É justo dizer que a maioria dos usos de GC.Collect () é uma má ideia e eu entrei nisso com alguns detalhes na postagem original, então não vou repetir tudo isso aqui. Então, vamos prosseguir para ...

Regra # 2

Considere chamar GC.Collect () se algum evento não recorrente acabou de acontecer e é muito provável que esse evento tenha causado a morte de muitos objetos antigos.

Um exemplo clássico disso é se você estiver escrevendo um aplicativo cliente e exibir um formulário muito grande e complicado que possui muitos dados associados a ele. Seu usuário acabou de interagir com este formulário, potencialmente criando alguns objetos grandes ... coisas como documentos XML ou um grande DataSet ou dois. Quando o formulário fecha, esses objetos estão mortos e, portanto, GC.Collect () irá recuperar a memória associada a eles ...

Portanto, parece que essa situação pode se enquadrar na Regra # 2, você sabe que há um momento em que muitos objetos antigos morreram e isso não é recorrente. No entanto, não se esqueça das palavras de despedida de Rico.

A regra # 1 deve superar a regra # 2 sem evidências fortes.

Meça, meça, meça.

Jon Norton
fonte
9
Eu diria que isso é apenas uma coisa velha. Nada é realmente ruim ou perigoso se você sabe o que está fazendo e, portanto, sabe quando e como fazer, bem como seus efeitos colaterais. Coisas como nunca, nunca use xxxx são colocadas lá para proteger o mundo de programadores ruins: D
Jorge Córdoba
veja também stackoverflow.com/questions/233596/…
Ian Ringrose
Não estou dizendo que usar GC.Collect é uma boa prática. Mas às vezes é uma maneira rápida de resolver problemas sem saber sua causa real. É feio, eu sei, mas funciona, e não me parece uma abordagem ruim, especialmente quando não há muito tempo para descobrir a causa raiz do problema e seu chefe está atrás de você ... você sabe.
Silent Sojourner
58

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

Aaron Fischer
fonte
3
Isso é verdade, mas não sei se eles poderiam fazer suposições que se aplicam a todos os desenvolvimentos.
MasterMastic,
2
@Ken Não, eles não podem. Mas você está em uma posição melhor para fazer isso? Ou você vai escrever código assumindo um hardware específico, uma versão específica do sistema operacional e assim por diante? A relação dor / ganho está muito alta neste.
The Dag
2
@TheDag IMO, claro que sou. Quando estou liberando memória e outras coisas, realmente não me importo com o hardware, porque esse é o trabalho do sistema operacional para lidar com isso. Eu também não me importo com o sistema operacional porque tenho uma interface comum a todos aqueles para os quais estou programando. (por exemplo, não me importo se é Windows, Mac ou Linux: quando estou alocando / liberando memória em C / C ++ é novo / delete malloc / dealloc). Eu sempre posso estar errado, então sinta-se à vontade para me corrigir.
MasterMastic
@MasterMastic malloctem apenas uma interface muito simples, e suas implementações podem variar o suficiente para importar. Tudo depende do tipo de problema que você está tentando resolver. Se mallocfosse "bom o suficiente", você não precisaria de buffer pooling, não é? O desenvolvimento em C / C ++ está cheio de exemplos em que você tenta adivinhar o sistema operacional / tempo de execução / bibliotecas porque você conhece melhor (e às vezes, realmente sabe). Muitos aplicativos de desempenho crítico evitam usar alocadores de sistema / tempo de execução inteiramente. Jogos usados ​​para pré-alocar toda a memória na inicialização (arrays de tamanho constante, etc.).
Luaan
24

Então, que tal quando você estiver usando objetos COM, como MS Word ou MS Excel do .NET? Sem ligarGC.Collect depois de liberar os objetos COM, descobrimos que as instâncias do aplicativo Word ou Excel ainda existem.

Na verdade, o código que usamos é:

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 incorreto do coletor de lixo? Se sim, como fazemos com que os objetos Interop morram? Além disso, se não foi feito para ser usado dessa forma, por que o método de GCé Collectpar Public?

Dib
fonte
3
Isso seria uma grande questão sobre o StackOverflow, ou seja: Como erradicar as instâncias COM sem chamar o GC. Com atenção especial às referências circulares não gerenciadas. É um dos desafios que me fez ter medo de atualizar meu suplemento VB6 Outlook para C #. (Fizemos muito trabalho para desenvolver padrões de codificação e casos de teste no lado do VB que garantiam que as referências COM fossem eliminadas de maneira determinística quando não fossem mais necessárias).
rkagerer
2
Se isso se aplica a objetos COM em geral, talvez este seja um cenário válido. Mas, de cara, eu diria que o problema provavelmente é que você está usando um aplicativo cliente projetado para uma área de trabalho interativa como um servidor COM. Da base de conhecimento do MSDN: "Atualmente, a Microsoft não recomenda e não oferece suporte para a automação de aplicativos do Microsoft Office de qualquer aplicativo ou componente cliente autônomo e não interativo (incluindo ASP, ASP.NET, DCOM e NT Services), porque o Office pode apresentar um comportamento instável e / ou bloqueio quando o Office é executado neste ambiente. "
The Dag
2
@TheDag - A Microsoft pode não recomendar, mas muitos de nós tiveram que portar o código VB6 antigo com a interoperabilidade do Office para aplicativos do Windows .Net. Passei meses trabalhando até que finalmente me livrei de todas as referências invisíveis penduradas para um grande projeto de conversão de VB6 para .Net. Aprender a liberar em ordem inversa de atribuição e manter referências locais para CADA objeto de comunicação único, incluindo as coleções, ajudou.
Dib
15

Bem, o GC é uma daquelas coisas com as quais tenho uma relação de amor / ódio. Nós quebramos no passado através do VistaDB e postamos em um blog sobre isso. Eles consertaram, mas leva MUITO tempo para obter soluções deles em coisas como esta.

O GC é complexo e uma abordagem de tamanho único é muito, muito difícil de aplicar em algo tão grande. A MS fez um bom trabalho, mas às vezes é possível enganar o GC.

Em geral, você não deve adicionar um a Collectmenos que saiba com certeza que acabou de se desfazer de uma tonelada de memória e ela entrará em crise de meia-idade se o GC não limpar agora.

Você pode bagunçar a máquina inteira com uma série de GC.Collectdeclarações ruins . A necessidade de uma instrução collect quase sempre aponta para um erro subjacente maior. O vazamento de memória geralmente tem a ver com referências e falta de compreensão de como funcionam. Ou usar o IDisposableem objetos que não precisam dele e colocar uma carga muito maior no GC.

Observe de perto a% de tempo gasto no GC por meio dos contadores de desempenho do sistema. Se você vir seu aplicativo usando 20% ou mais do seu tempo no GC, você tem sérios problemas de gerenciamento de objetos (ou um padrão de uso anormal). Você deseja sempre minimizar o tempo que o GC gasta, pois isso irá acelerar todo o seu aplicativo.

Também é importante observar que o GC é diferente em servidores e em estações de trabalho. Eu vi uma série de pequenos problemas difíceis de rastrear com pessoas que não testam os dois (ou nem mesmo sabem que são dois).

E apenas para ser o mais completo possível em minha resposta, você também deve testar no Mono se estiver direcionando essa plataforma também. Uma vez que é uma implementação totalmente diferente, pode ocorrer problemas totalmente diferentes da implementação do MS.

Jason Short
fonte
O culpado geralmente são os eventos. Sempre que um método de instância é usado como um manipulador de eventos, o publicador do evento tem uma referência ao assinante por meio do delegado de evento. A única maneira "fácil" de evitar problemas com isso é usar apenas editores que tenham no máximo a mesma vida dos assinantes (por exemplo, um TextBox publicando um evento tratado pelo formulário que o contém não é problema, pois o textbox não é suposto viver fora da forma). Exemplo de cenário de problema: modelo Singleton, visualizações temporárias que tratam de eventos de modelo.
The Dag
5
Como podemos bagunçar a máquina inteira?
Adam R. Gray
13

Existem situações em que é útil, mas em geral deve ser evitado. Você poderia compará-lo ao GOTO, ou andar de motocicleta: você faz isso quando precisa, mas não conta para seus amigos.

Rjohnston
fonte
12

Pela 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 suas vantagens em ajudar a esclarecer possíveis vazamentos de memória. Acho que minha razão fundamental é que o GC foi escrito e otimizado por programadores muito mais inteligentes do que eu, e se eu chegar a um ponto que sinto que preciso chamar GC.Collect (), é uma pista de que saí do caminho algum lugar. Na sua situação, não parece que você realmente tenha problemas de memória, apenas que está preocupado com a instabilidade que a coleção trará para o seu processo. Visto que ele não limpa os objetos ainda em uso e que se adapta muito rapidamente às demandas crescentes e decrescentes, acho que você não terá que se preocupar com isso.

TheZenker
fonte
10

Um dos maiores motivos para chamar GC.Collect () é quando você acaba de realizar um evento significativo que cria muito lixo, como o que você descreveu. Chamar GC.Collect () pode ser uma boa ideia aqui; caso contrário, o GC pode não entender que foi um evento 'único'.

Claro, você deve criar um perfil e ver por si mesmo.

TraumaPony
fonte
9

Bem, obviamente você não deve escrever código com requisitos de tempo real em linguagens com coleta de lixo em tempo não real.

Em um caso com estágios bem definidos, não há problema em acionar o coletor de lixo. Mas este caso é extremamente raro. O problema é que muitos desenvolvedores tentarão usar isso para encobrir os problemas em um estilo cult de carga, e adicioná-lo indiscriminadamente causará problemas de desempenho.

wnoise
fonte
Verdade. Mas testes automatizados capazes de capturar a condição de erro "objeto não elegível para coleta de lixo, mas deveria ser" seriam valiosos. Isso pode ser alcançado por meio de uma combinação de lógica de fábrica, lógica destruidora e GC.Collect. Por exemplo, sua classe Entity tem uma propriedade IObjectTracker, normalmente nula, mas atribuída pela fábrica de entidade de propósito de teste. A fábrica também notifica o rastreador do nascimento do objeto, enquanto o destruidor o notifica (quando presente) da morte. Se você souber que "o destrutor foi executado para todos os objetos colecionáveis ​​de lixo", poderá verificar o estado do rastreador para detectar vazamentos.
The Dag
7

Chamar GC.Collect () força o CLR a fazer um rastreamento de pilha para ver se cada objeto pode ser realmente liberado verificando as referências. Isso afetará a escalabilidade se o número de objetos for alto e também é conhecido por acionar a coleta de lixo com muita frequência. Confie no CLR e deixe o coletor de lixo rodar sozinho quando apropriado.

Ta01
fonte
2
Você não apenas causa o stack walk, mas o thread principal de seus aplicativos (e todos os threads filhos que ele criou) são congelados para que o GC possa andar na pilha. Quanto mais tempo seu aplicativo passa em GC, mais tempo ele fica congelado.
Scott Dorman
3
Estou mais preocupado com uma falha de aplicativo devido a uma exceção de falta de memória do que com o desempenho lento porque o aplicativo / GC estava descartando coisas que não são mais necessárias. Alguém sabe por que a Microsoft parece lançar uma exceção OOM sem FIRST jogar o lixo fora? (Sem esta etapa ÓBVIA - ou pelo menos uma explicação de por que esta etapa não parece ser tentada antes de lançar a exceção OOM, não tenho certeza se tenho fé nas coisas acontecendo "automaticamente" da "maneira que deveriam".
Wonderbird de
6

Na verdade, não acho uma prática muito ruim ligar para GC.Collect.
Pode haver casos em que precisamos disso. Por exemplo, eu tenho um formulário que executa um thread, que por sua vez abre tabelas diferentes em um banco de dados, extrai o conteúdo de um campo BLOB para um arquivo temporário, criptografa o arquivo e, em seguida, lê o arquivo em um fluxo binário e de volta em um BLOB campo em outra tabela.

Toda a operação consome muita memória e não é certo sobre o número de linhas e o tamanho do conteúdo do arquivo nas tabelas.

Eu costumava obter OutofMemory Exception com frequência e pensei que seria sábio executar GC.Collect periodicamente com base em uma variável de contador. Eu incremento um contador e quando um nível especificado é alcançado, o GC é chamado para coletar qualquer lixo que possa ter se formado e para recuperar qualquer memória perdida devido a vazamentos de memória imprevistos.

Depois disso, acho que está funcionando bem, pelo menos sem exceção !!!
Eu ligo da seguinte maneira:

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

Em .net, o tempo necessário para realizar uma coleta de lixo está muito mais fortemente relacionado à quantidade de coisas que não são lixo do que à quantidade de coisas que são. Na verdade, a menos que um objeto seja substituído Finalize(explicitamente ou por meio do destruidor C #), seja o alvo de a, esteja WeakReferenceno Large Object Heap ou seja especial em alguma outra forma relacionada ao gc, a única coisa que identifica a memória na qual está como objeto é a existência de referências enraizadas a ele. Caso contrário, a operação do GC é análoga a tirar de um edifício tudo de valor e dinamitar o edifício, construir um novo no local do antigo e colocar todos os itens valiosos nele. O esforço necessário para dinamitar o prédio é totalmente independente da quantidade de lixo dentro dele.

Conseqüentemente, a chamada GC.Collecttende a aumentar a quantidade total de trabalho que o sistema precisa realizar. Isso atrasará a ocorrência da próxima coleção, mas provavelmente fará tanto trabalho imediatamente quanto a próxima coleção teria exigido quando ocorreu; no ponto em que a próxima coleta teria ocorrido, a quantidade total de tempo gasto coletando terá sido aproximadamente o mesmo que GC.Collectnão foi chamado, mas o sistema terá acumulado algum lixo, fazendo com que a coleta seguinte seja exigida mais cedo do que GC.Collectnão foi chamado.

Os momentos em que posso ver que são GC.Collectrealmente úteis são quando é necessário medir o uso de memória de algum código (uma vez que os números de uso de memória só são realmente significativos após uma coleção) ou o perfil de qual dos vários algoritmos é melhor (chamando GC.Collect () antes de executar cada uma das várias partes do código pode ajudar a garantir um estado de linha de base consistente). Existem alguns outros casos em que alguém pode saber coisas que o GC não sabe, mas a menos que se esteja escrevendo um programa de thread único, não há como saber que uma GC.Collectchamada que ajudaria as estruturas de dados de um thread a evitar "crise de meia-idade "não faria com que os dados de outros tópicos tivessem uma" crise de meia-idade "que de outra forma teria sido evitada.

supergato
fonte
5

Criação de imagens em loop - mesmo se você chamar dispose, a memória não será recuperada. Recolha de lixo sempre. Passei de 1,7 GB de memória em meu aplicativo de processamento de fotos para 24 MB e o desempenho é excelente.

Você precisa absolutamente de tempo para ligar para GC.Collect.

Vale
fonte
2
Vocação Disposeé não deveria liberar memória gerenciada. Você parece não saber como funciona o modelo de memória do .NET.
Andrew Barber,
4

Tivemos um problema semelhante com o coletor de lixo não coletando lixo e liberando memória.

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

O programa em um ambiente de 32 bits (x86) travaria com um erro de "falta de memória". Conseguimos executá-lo em um ambiente x64, mas queríamos uma solução melhor.

Encontramos um.

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

Chamar o GC de dentro da sub-rotina não funcionou. A memória nunca foi recuperada ...

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

Movendo a chamada GC para fora do escopo da sub-rotina, o lixo foi coletado e a memória foi liberada.

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 outras pessoas que estão frustradas com a coleta de lixo do .NET quando ela parece ignorar as chamadas para GC.Collect() .

Paul Smith

Paul Smith
fonte
4

Não há nada de errado em chamar explicitamente para uma coleção. Algumas pessoas realmente querem acreditar que, se for um serviço prestado pelo fornecedor, não o questione. Ah, e todos aqueles congelamentos aleatórios nos momentos errados do seu aplicativo interativo? A próxima versão o tornará melhor!

Deixar que um processo em segundo plano lide com a manipulação da memória significa não ter que lidar com isso nós mesmos, é verdade. Mas isso não significa logicamente que seja melhor para nós não lidarmos com isso nós mesmos, em todas as circunstâncias. O GC é otimizado para a maioria dos casos. Mas isso não significa logicamente que seja otimizado em todos os casos.

Você já respondeu a uma pergunta aberta como 'qual é o melhor algoritmo de classificação' com uma resposta definitiva? Nesse caso, não toque no GC. Para aqueles de vocês que solicitaram as condições ou deram respostas do tipo 'neste caso', podem prosseguir para aprender sobre o GC e quando ativá-lo.

Tenho que dizer que tive congelamentos de aplicativos no Chrome e no Firefox que me deixaram muito frustrado e, mesmo assim, em alguns casos, a memória cresce sem obstáculos - se eles aprendessem a chamar o coletor de lixo - ou me dessem um para que, ao começar a ler o texto de uma página, eu possa acertá-lo e, assim, ficar livre de congelamentos pelos próximos 20 minutos.

Gerard ONeill
fonte
2

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 adicionar pressão de memória como uma dica ao GC de que ele deve realizar uma coleta em breve.

Sergio Acosta
fonte
2
Interessante, mas a documentação diz que AddMemoryPressure deve ser usado quando 'um pequeno objeto gerenciado aloca uma grande quantidade de memória não gerenciada'. (ênfase minha)
Robert Paulson
2

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

Roubar
fonte
1
A natureza heurística do coletor de lixo e o fato de que eles expuseram essa funcionalidade para o mundo externo me fazem pensar nele como algo que é útil se usado onde precisa estar. O problema não é usá-lo, mas saber como, onde e quando usá-lo.
Trap
Sem mencionar o melhor conhecimento dos GCs sobre todos os outros aplicativos e suas necessidades de memória. O GC negocia a memória com o SO e, como tal, é afetado pela memória física disponível e todos os outros processos na máquina, tanto gerenciados como não gerenciados. Embora eu duvide que o GC realmente saiba "quando é um bom momento para coletar" em uma base "caso a caso", é muito provável que tenha uma estratégia geral melhor do que ... QUALQUER aplicativo único. ;)
The Dag
2

O desejo de chamar GC.Collect () geralmente é tentar encobrir os erros que você cometeu em outro lugar!

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

Sam
fonte
5
isso talvez seja uma generalização
MickyD
1

Resumindo, você pode criar o perfil do aplicativo e ver como essas coleções adicionais afetam as coisas. Eu sugiro ficar longe dele, a menos que você vá para o perfil. O GC é projetado para cuidar de si mesmo e, conforme o tempo de execução evolui, eles podem aumentar a eficiência. Você não quer um monte de código por aí que pode atrapalhar o trabalho e não ser capaz de tirar vantagem dessas melhorias. Há um argumento semelhante para usar foreach em vez de para, sendo que futuras melhorias ocultas podem ser adicionadas a foreach e seu código não precisa ser alterado para tirar proveito.

Christopher Elliott
fonte
1

O .NET Framework em si nunca foi projetado para ser executado em um ambiente de tempo real. Se você realmente precisa do processamento em tempo real, pode usar uma linguagem de tempo real incorporada que não seja baseada em .NET ou usar o .NET Compact Framework em execução em um dispositivo Windows CE.

Scott Dorman
fonte
Ele pode estar usando o .Net Micro Framework, que foi projetado para ambientes de tempo real.
TraumaPony
@TraumaPony: Verifique o gráfico na parte inferior desta página msdn.microsoft.com/en-us/embedded/bb278106.aspx : Claramente, o Micro Framework não foi projetado para ambientes em tempo real. Ele foi, no entanto, projetado para ambientes embarcados (como WinCE), mas com requisitos de energia mais baixos.
Scott Dorman
1

O pior que pode fazer é congelar um pouco o seu programa. Então, se estiver tudo bem para você, faça. Normalmente não é necessário para aplicativos de cliente ou web com interação principalmente do usuário.

Eu descobri que às vezes programas com threads de longa execução, ou programas em lote, obterão a exceção OutOfMemory, embora estejam descartando objetos corretamente. Lembro-me de um processamento de transações de banco de dados de linha de negócios; a outra era uma rotina de indexação em um thread de segundo plano em um aplicativo cliente espesso.

Em ambos os casos, o resultado foi simples: Não GC.Collect, out of memory, consistentemente; GC.Collect, desempenho perfeito.

Tentei resolver problemas de memória várias outras vezes, sem sucesso. Eu tirei.

Resumindo, não coloque, a menos que esteja recebendo erros. Se você colocá-lo e ele não resolver o problema de memória, retire-o. Lembre-se de testar no modo Release e comparar maçãs com maçãs.

A única vez que as coisas podem dar errado é quando você se torna moralista a respeito. Não é uma questão de valores; muitos programadores morreram e foram direto para o céu com muitos GC.Collects desnecessários em seus códigos, que sobrevivem a eles.

FastAl
fonte