Javascript apresenta vazamentos de memória ? Se sim, como evitá-lo? Tendo em conta que várias pessoas me fizeram perguntas semelhantes recentemente, parece que ninguém estudou sistematicamente esta parte do conteúdo. Portanto, pretendo compartilhar com vocês algumas informações que compilei há alguns anos.
Em primeiro lugar, pode-se dizer com certeza que algumas formas de escrever JavaScript causarão vazamentos de memória, pelo menos no IE6. Portanto, hoje, quando o IE6 se recusa a se aposentar, ainda precisamos entender o conhecimento relevante (embora na maioria dos casos, o vazamento de memória causado pelo js não seja o principal motivo da lentidão do computador). A pesquisa relevante está concentrada principalmente nos anos 2005-07. Este artigo não traz nenhuma ideia nova. Se você tem amigos que o estudaram naquela época, você pode simplesmente ignorá-lo.
Como desenvolvedor front-end, ao entender esses problemas, você precisa saber o que são e por quê. Portanto, antes de apresentar vazamentos de memória js, vamos começar explicando por que há vazamentos de memória.
Ao falar sobre vazamentos de memória, temos que falar sobre a forma como a memória é alocada. Existem três maneiras de alocar memória, a saber:
1. Alocação Estática: A forma de alocação de variáveis estáticas e variáveis globais. Se pensarmos em uma sala como um programa, podemos pensar na memória alocada estaticamente como um móvel durável na sala. Normalmente, eles não precisam ser descartados e reciclados porque ninguém joga armários pela janela como lixo todos os dias.
2. Alocação Automática: Um método de alocação de memória para variáveis locais na pilha. A memória na pilha pode ser liberada automaticamente com a operação pop quando o bloco de código termina.
Isso é semelhante a pessoas que vêm a uma sala para fazer coisas. Depois que as coisas forem feitas, elas sairão por conta própria e o espaço que ocupam será liberado automaticamente à medida que essas pessoas saírem.
3. Alocação Dinâmica: Um método de alocação dinâmica de espaço de memória na pilha para armazenar dados. Ou seja, a memória aplicada para usar malloc ou new quando o programa está em execução, precisamos liberá-la nós mesmos usando free ou delete. A vida útil da memória dinâmica é determinada pelo programador. Se você esquecer de liberá-lo, inevitavelmente causará um vazamento de memória. Nesse caso, os blocos de memória empilhados são como os guardanapos que usamos todos os dias. Depois de usá-los, temos que jogá-los na lata de lixo, caso contrário a casa ficará uma bagunça. Portanto, os preguiçosos sonham em ter um robô doméstico para limpar com eles. No desenvolvimento de software, se você tem preguiça de liberar memória, também precisa de um robô semelhante - que na verdade é um coletor de lixo implementado por um algoritmo específico. São precisamente alguns defeitos no próprio mecanismo de coleta de lixo que levam a vazamentos de memória do JavaScript.
Há alguns anos, li um artigo chamado “Uma História Interessante da Reciclagem de Lixo”, que explicava detalhadamente o mecanismo de coleta de lixo.
Assim como a superalimentação, uma tecnologia usada por muitos carros de luxo como ponto de venda, que na verdade foi usada pela Mercedes-Benz na década de 1910, a tecnologia de reciclagem de lixo já existe há muito tempo. A linguagem Lisp, nascida no MIT por volta de 1960, foi a primeira linguagem que dependia fortemente da tecnologia de alocação dinâmica de memória. Quase todos os dados no Lisp aparecem na forma de "tabelas", e o espaço ocupado pelas "tabelas" está na pilha. alocado dinamicamente. O recurso inato de gerenciamento de memória dinâmica da linguagem Lisp exige que os projetistas da linguagem Lisp resolvam o problema de liberação automática de cada bloco de memória no heap (caso contrário, os programadores Lisp serão inevitavelmente sobrecarregados por inúmeras instruções free ou delete no programa) Isso levou diretamente ao nascimento e ao desenvolvimento da tecnologia de coleta de lixo.
Os três algoritmos mais básicos de coleta de lixo também apareceram juntos naquela época. Vamos dar uma olhada neles um por um:
Algoritmo de contagem de referência: Este pode ser o primeiro método que vem à mente. Em termos figurados, a contagem de referência pode ser entendida desta forma. Há muitos papéis brancos em casa, e esses papéis são como memórias. Usar a memória é como escrever nesses pedaços de papel. A memória pode ser usada à vontade, mas há uma condição. Quem usar um pedaço de papel deve escrever uma contagem de 1 no canto do papel. Se duas pessoas usarem um pedaço de papel ao mesmo tempo, a contagem passa a ser. 2 e assim por diante. Quando uma pessoa termina de usar um pedaço de papel, a contagem no canto deve ser diminuída em 1. Dessa forma, quando a contagem chegar a 0, as condições de coleta de lixo serão atendidas e o robô que está esperando ao lado jogará imediatamente o papel no caixa de lixo. O coletor de lixo baseado em contador de referência é executado mais rapidamente, não interrompe a execução do programa por muito tempo e é adequado para programas que devem ser executados em tempo real. Porém, o contador de referências aumenta o overhead de execução do programa, ao mesmo tempo, há outro grande problema. Este algoritmo apresenta uma falha, ou seja, uma vez gerada uma referência circular, a memória vazará. Por exemplo, novos dois objetos a e b neste momento, as contagens de a e b são ambas 1. Então, apontamos um atributo de a para b, e um atributo de b para a. o Relacionamento de referência, as contagens de aeb se tornam 2. Quando o programa termina e sai do escopo, o programa diminui automaticamente a contagem de a em 1. Como a contagem de a no final ainda é 1, a não será liberado. Da mesma forma, a contagem final de b também é 1, b não será liberado e a memória simplesmente vazou!