Se o problema é indecidível, como ele faz?
Para entender melhor vamos entender que existem basicamente duas formas de organizar a memória (certamente poderíamos falar em uma terceira que é estática mas essa é simples de entender e gerenciar, porque ela está lá no programa e não precisa haver nenhuma preocupação ou mecanismo.
Outra memória muito importante é a pilha. O ideal seria usá-la porque o gerenciamento é muito simples e eficiente, tem até instrução no processador para facilitar isso, e o compilador já coloca para você quando desalocar (na verdade quando pode voltar usar aquele trecho de novo). Esta memória é chamada de automática.
Nem sempre o ideal é possível por várias razões e precisamos de alocação de memória dinâmica, algo proibido em certos tipos de aplicação, mas presente na esmagadora maioria do que fazemos. Ela é mais flexível e permite algumas coisas que a pilha não permite, especialmente com objetos grandes, muito objetos ou com tempo de vida difícil de determinar na compilação ou que extrapola a pilha. Aí o programador aloca essa memória de forma explícita ou implícita e depois alguém fica responsável por desalocar ou fazer algo que indique que ela não será mais usada e poder usar para outra coisa, atém mesmo devolver para o sistema operacional. Em alguns caos é fácil determinar quando isso ocorrerá, outros nem tanto. Mesmo sendo fácil o tradicional é contarmos co ma atenção do programar para "desalocar" a memória que ele alocou no momento correto, nem antes nem depois do deveria, especialmente se esse depois for tarde demais.
Memória dinâmica é extremamente ineficiente, muitos programas só podem ser otimizados fortemente lidando bem com ela, mais do que tentar otimizar o processador. Mas é um mal necessário. E tem linguagens que nem ligam, ao ponto que só possuem essa memória, chamada de heap.
Algumas linguagens não querem dar esse fardo para o programador, até porque ele erra muito isso em vários casos, especialmente linguagens que tem controles de fluxos indeterminados (as que tem exceções por exemplo que é um goto
muito pior mas que é defendido por muitos, mesmo aqueles que são contra o goto
, vai entender...)
Desta forma pode ter vários mecanismos que coleta essa memória que não precisa mais ser usada.
Exatamente o que se caracteriza um GC pode haver controvérsia. Porque um dos mecanismos é usado quando o compilador determina o momento de desalocar e colocar o "comando" necessário lá para fazer isso. Eu tendo a não classificar isso como GC porque todo o processo é feito pelo compilador. Mas não vou dizer que está errado considerar que ele é uma forma de GC.
Outra muito popular é a de contagem de referência, ou seja, o objeto possui um contador que sempre que alguém se referencia ao objeto é incrementado e quando a referência some é decrementado, e chegando a zero ele manda desalocar a memória. Este caso há um mecanismo em tempo de execução que determina a coleta dos dados, pra mim não tem discussão isso é um GC. Mas não vou brigar com quem acha que não é.
Daí temos os GCs mais sofisticados, não determinísticos com suas vantagens e desvantagens, em geral chamados de tracing garbage collectors que vai deixando alocar tudo sem muito controle, em alguns casos chega ser até tão eficiente quanto aloca na pilha e em algum momento ele vai para seu programa, analisar a memória e decidir quais objetos não possuem mais referência para saber que eles podem ser descartados.
Alguns vão apagar os objetos, outros copiarão os objetos que vão sobreviver para outra lugar, que tem vantagens e desvantagens.
Alguns desses GCs já são tão sofisticados (e alguns absurdamente caros) que eles fazem esse trabalho de uma forma que quase não dá para perceber que tem uma parada de execução do programa principal. Mesmo assim não dá para fazer aplicações hard real time, da mesma forma que nem com gerenciamento manual dá.
Um programa que não libera a memória tem potencial de ocupar toda a RAM e até a memória virtual em memória de massa, chegando travar a aplicação. A parte boa é que o fim de um programa libera toda a memória da aplicação de uma vez sem maiores problemas ou preocupações pelo programador.
Em tese um GC elimina esse problema, a não ser que ele seja mal feito ou tenha algum mecanismo na linguagem que complique o GC.
Por exemplo o RefCount que falei antes tem um problema quando há referência circulares entre objetos, mesmo que indiretamente porque um não deixa matar o outro que ainda está vivo mas deveria morrer. Sabendo usar, dá tudo certo, até porque raras as estruturas de dados que se tornam circulares e tem como se proteger nesses casos, mas dá um trabalhinho para o programador.
Quando se busca por referências vivas, o tal do tracing, de uma forma ou de outra quase todos os GCs em algum momento usam um mecanismo de mark & sweep, ou seja, marca os objetos que devem morrer ou viver e depois se livra deles, e a forma pode ser muito simples ou extremamente complexa. Mas GCs mais sofisticados possuem outros mecanismos como prioridade.
Alguns trabalham com gerações já que é comum os objetos durarem muito pouco ou muito tempo. Alguns são tão sofisticados com isso que trabalham como se fosse trens e vagões, não vou entrar em detalhes.
GCs podem ser mais eficientes que o gerenciamento de memória, mas não é fácil isso acontecer e muitas vezes não se está comparando de forma justa ou pegando casos bem isolados. Em geal eles são mais caros. Mas o fato dele alocar de forma simples e deslocar muitas vezes em bloco pode ser mais rápido que ficar dando malloc()
e free()
na mão, embora é provável que se for uma situação que isso esteja atrapalhando o programar adotará um mecanismo que ele não precise fazer isso tanto, ou seja, ele fará algo parecido com um GC.
GC é ótimo para a maioria das tarefas e é preferível do que gerenciar a memória na não, por isso você precisa ter um bom motivo para usar C, C++, Rust e outras linguagens do tipo, mesmo as últimas tendo uma forma de GC, mas dá trabalho.
GC é uma das áreas que mais se pesquisa para obter melhores resultados.
- https://pt.stackoverflow.com/q/255769/101
- https://pt.stackoverflow.com/q/3797/101
- https://pt.stackoverflow.com/q/56580/101
- https://pt.stackoverflow.com/q/254358/101
- https://pt.stackoverflow.com/q/50165/101
- https://pt.stackoverflow.com/q/43766/101
- https://pt.stackoverflow.com/q/252011/101
- https://pt.stackoverflow.com/q/280973/101
S2
Farei algo que muitos pedem para aprender a programar corretamente, gratuitamente (não vendo nada, é retribuição na minha aposentadoria) (links aqui no perfil também).