Executando verificação de segurança...
1

[ Contéudo ] Como o Garbage Collector funciona?

Introdução:

Esse é um assunto que vejo sendo pouco comentado nas comunidades de programação voltadas para o JavaScript... E pouco se fala sobre vazamento de memória que é o Garbage Collector ameniza.

Um dia desses eu fiz uma pergunta por aqui, infelizmente eu não tive respostas sobre vazamentos de memória. Obviamente pesquisei mais, porém, pouco encontrei. Entretanto, achei um conteúdo bem interesse que elucida muito bem sobre Garbage Collector e como evita vazamento de memória de forma mais apropriedade.

Observações:

No final, vou deixar o site que citei como fonte. O que eu quero enfatizar é que eu não necessariamente vou traduzir o artigo e sim expor o que aprendi nele, e adapta-lo da forma que eu acredito que seja de mais fácil entendimento.

Existe alguns trechos e exemplos que irei trazer para cá do artigo, pois acredito que melhorará o entendimento, mas somente isso. Como eu disse anteriormente, não é necessariamente uma tradução, e sim uma adapatação para uma forma que eu acredito que seja melhor de entender.

O que é gerenciamento de memória?

Antes de tudo, precisamos entender o que é gerenciamento de memória. Gerenciamento de memória, como o próprio nome já sugeste, é o ato de gerenciar a memória para que não ocorra problemas de perfomance, vazamento de memória, dentre outras causas que não citarei para não tangenciar muito o assunto.

Linguagens de programação como C, C#, dentre outras, possui formas de gerenciar memória de maneira manual. O que significa que o programador vai explicitamente determina o que entra e o que sai da memória e quando isso deve acontecer.

Como já citei algumas vezes, vazamento de mémoria é um dos principais problemas que ocorrem quando o programador não se preocupa com este problema.

O que é vazamento de memória?

Vazamento de memória é quando alocamos memória, e mesmo quando não estamos mais usando esse valor, ele permance da memória.

É como se abríssemos algo para usar, usamos, e depois que usamos não precisamos mais disso, e é natural que não queiramos que isto continue usando memória, então devo liberar, mas continua lá, alocado na memória.

example

No exemplo acima eu demonstro um caso muito comum. Temos um evento sem eventos, depois que adicionamos um evento, este evento agora está alocado na memória. Quando utilizamos o evento, ele continua alocado na memória, mesmo quando não estamos utilizando ele (disparando o evento).

Isso quer dizer que devemos remover todos os ouvintes de evento? A resposta é não. Existe memória que deve permancer o tempo todo (memória ativa), mesmo ela não seja usada, depende muito do projeto, mas dando o exemplo de um modal.

Num modal, podemos ter um botão que dispara um evento, mas ai é que tá o problema. O modal só precisa de um ouvinte de evento, quando o modal está ativo, quando fechado, se faz necessário remover este ouvinte de evento para não alocar memória de forma desnecessária. Então ao fechar o modal, você pode adicionar uma instrução junto com a função que o fecha para remover ouvintes e na função que abre adicionar os ouvintes.

Isso foi um exemplo básico sobre o que é vazamento de memória. Lembrando que cada caso é um caso, atente-se as necessidade de seu projeto.

Garbage Collector

Como eu disse um pouco mais acima, toda linguagem de uma forma de gerenciamente de memória, e o JavaScript não é diferente. A diferença é que em linguagens como C, se faz o gerencimento de forma manual, já no JavaScript isso se faz de forma automática, o que é bom, mas gera alguns problemas.

Algoritmo do Garbage Collector:

  • A partir da raiz, o Garbage collector vai analisando tudo e "marca" todos os valores
  • Depois, o garbage collector vai em todos os objetos "marcados" e marca sua referência
  • Isso só acontece uma vez, então o garbage collector não repete o processo para objectos já marcados
  • Depois de visitar tudo que foi marcado, o garbage collector elimina tudo aquilo que não foi marcado.

Ok, falmos de "marcado", de analise e etc... Em resumo, Garbage collector vai analisar a partir da raiz, todos os objetos e marcar eles, para assim, identifica-los posteriomente. Isso tem dois objetivos, marcar objetos para que não repita o processo novamente com eles, e marca-los para saber que o objeto em questão é "acessível", então possui uma referência, assim, ele não será coletado pelo o Garbage collector e eliminado da memória.

Referência:

O conceito fundamental do Garbage collector são referência, pois é com isso que ele determina aquilo que pode ou não ser marcado. Exemplos:

let user = {
  name: "John"
};

Aqui user tem uma referência para um objeto.

example

A variável global user faz referência para um objeto. Dito isso, o garbage collector não consegue coletar aquilo que possui uma referência, pois ele julga que: se tem referência, ele ainda é útil para aplicação.

Agora, vamos ver como remover essa referência:

user = null

example

Se não existe mais nada que aponte para algo (uma referência), então o Garbage collector coleta esse valor e remove da memória, pois se não existe referências, ele não é mais útil.

O problema começa quando temos mais de uma referência:

let user = {
  name: "John"
};

let admin = user;

example

Agora, se fizermos isso:

user = null

O objeto não será apagado, pois admin ainda faz referência para o objeto! Por isso que ocorre muitos vazamento de memória! Para resolver isso, ambos user e admin precisam para de fazer referência para o objeto.

Agora indo para um exemplo ainda mais complexo:

function marry(man, woman) {
  woman.husband = man;
  man.wife = woman;

  return {
    father: man,
    mother: woman
  }
}

let family = marry({
  name: "John"
}, {
  name: "Ann"
});

example

Aqui temos um exemplo muito mais complexo que os anteriores, pois possui mais referências. Vamos deletar algumas coisas:

delete family.father;
delete family.mother.husband;

example

Apagamos a referência de family para o objeto father e apagamos a referência para a husband, agora vai ficar assim:

example

Apenas o father foi eleminado pois não existe mais nada que faça referência para ele, mas para os outros objetos, ainda existe referência. então somente uma parte do todo é elminada da memória.

Agora, para eliminar tudo:

family = null;

example

Como family é que inicializa a raiz da referência, tendo como um valor null é o mesmo que cortar tuda a referência fora, pois tudo se inicia de family.

Conclusão:

Esse foi o fundamental de como o garbege collector se comporta. Ainda possui alguns detalhes que eu não entrei no mérito. Espero que tenham gostado.

Carregando publicação patrocinada...
4

O artigo está parcialmente correto, o que significa que está párcialmente errado. Tem vários pequenos pontos que etão errados. Não compromete a compreensão completa mas dará algumas ideias errdas para quem não entende nada do assunto.

Eu fiz uma resposta mas ela é voltada para C# (o que por sinal um dos erros é incluir C# como gerenciamento manual de memória). Não tenho uma de JavaScript, até mesmo porque não tem um só GC para ela, cada implementação pode usar um GC bem diferente do outro, e essa já é uma das ideias erradas. Eu tenho uma palestra longa (quase workshop) mais geral sobre GC, mas não adianta por os slides aqui porque sem o contexto do que eu falo também dará ideias erradas. Certamente farei um vídeo (uma série na verdade) sobre, só não sei quando.

O algoritmo citado é o mark and sweep, eu duvido que as implementações atuais de JS o usem porque ele é pouco performático.

Inclusive, gerenciamente automático de memória essencialmente toda linguagem faz, só a memória dinâmica que isso se diferencia. Abaixo tem como entender tudo isso melhor.

Eu não vou citar item por item de erros, mas para quem for ler já sabe que não aprenderá certo. Aprender sobre gerenciamento de memória até mesmo em linguagens que possuem GC é importante para programadores profissionais (para os outros provavelmente não), mas aprender errado pode eventualmente ser pior que não saber.

Pode ajudar mais: https://pt.stackoverflow.com/search?q=user%3A101+vazamento+de+mem%C3%B3ria e https://pt.stackoverflow.com/search?q=user%3A101+garbage+collector. E seguir links que vai encontrando. A questão é complexa.

Como eu sempre digo, a internet é a casa do capeta. Ela permitiu todos postarem oq ue quiser, a té o erro. E assim se faz cada vez mais, até porque um pega uma referência errada, não sabe disto, reproduz, provavelmente introduzindo mais erros e vai tendo cada vez mais conteúdo errado para solidificaro erro.

Ajudei? Era o meu desejo.


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).

1

EU li várias de suas respostas sobre GC e salvei a maioria delas. Gostei muito e elucidaram bastante coisas sobre o tópico. A Principio achava que o Garbage Collector existia apenas para JavaScript (bolha), mas vejo que existe para outras linguagens e funciona de maneira diferente. Muito obrigado.