Quando se trata de coleta de lixo (GC), muitas pessoas a associam naturalmente a Java. Em Java, os programadores não precisam se preocupar com a alocação dinâmica de memória e a coleta de lixo, tudo isso é deixado para a JVM para manusear.
Como o nome sugere, a coleção de lixo é liberar o espaço ocupado por lixo. Então, em Java, que tipo de objetos serão considerados "lixo"? Então, quando alguns objetos estão determinados a ser lixo, que estratégia deve ser usada para reciclar (liberar espaço)? Quais são os coletores típicos de lixo nas atuais máquinas virtuais comerciais? Vamos discutir essas questões uma a uma. Aqui está o esboço do diretório deste artigo:
Como determinar se um objeto é "lixo"?
Algoritmo típico de coleta de lixo
1. Como determinar se um objeto é "lixo"?
Nesta seção, primeiro entendemos a pergunta mais básica: se determinarmos que um objeto é "lixo"? Como a tarefa do coletor de lixo é reciclar o espaço ocupado pelo objeto de lixo para uso por novos objetos, como o coletor de lixo determina que um objeto é "lixo"? Ou seja, como julgar que um objeto pode ser reciclado.
Em Java, está associado a objetos por meio de referências, ou seja, se você deseja operar objetos, deve ser feito por meio de referências. Então é óbvio que uma maneira fácil é julgar se um objeto pode ser reciclado pela contagem de referência. Sem perder a generalidade, se um objeto não tiver referências associadas a ele, significa que o objeto é basicamente improvável de ser usado em outros lugares e, em seguida, o objeto se torna um objeto reciclável. Este método se torna o método de contagem de referência.
Este método é caracterizado por sua implementação e alta eficiência, mas não pode resolver o problema de referências circulares; portanto, esse método não é adotado no Java (o Python usa o método de contagem de referência). Veja o seguinte código:
classe pública principal {public static void main (string [] args) {myObject object1 = new MyObject (); MyObject Object2 = new MyObject (); object1.Object = Object2; object2.Object = Object1; objeto1 = nulo; objeto2 = nulo; }} classe myObject {public object = null;}As duas últimas frases atribuem objeto1 e objeto2 a nulo, o que significa que os objetos apontados pelo objeto1 e objeto2 não são mais acessíveis, mas como se referem um ao outro, sua contagem de referência não é 0, o coletor de lixo nunca os reciclará.
Para resolver esse problema, o método de análise de acessibilidade é adotado em Java. A idéia básica desse método é pesquisar em uma série de objetos "GC Roots" como ponto de partida. Se não houver um caminho acessível entre "raízes GC" e um objeto, o objeto é considerado inacessível. No entanto, deve -se notar que o objeto considerado inacessível pode não necessariamente se tornar um objeto reciclável. Um objeto que é julgado como inacessível deve passar por pelo menos dois processos de marcação para se tornar um objeto reciclável. Se ainda não houver possibilidade de se tornar um objeto reciclável durante esses dois processos de marcação, ele basicamente se tornará um objeto reciclável.
Quanto à forma como o método de análise de acessibilidade é operado, ainda não o entendi com muita clareza. Se algum amigo estiver mais claro, por favor me dê alguns conselhos.
Vamos ver um exemplo abaixo:
Objeto aobj = new object (); objeto bobj = new Object (); objeto cobJ = new Object (); aobj = bobj; aobj = cobJ; cobJ = null; aobj = null;
Qual linha pode tornar um objeto reciclável? O código na linha 7 fará com que os objetos se tornem objetos recicláveis. Quanto ao motivo pelo qual é deixado para os leitores pensarem por si mesmos.
Vamos dar uma olhada em outro exemplo:
String str = new String ("Hello"); softreference <String> sr = new SoftReference <String> (new String ("java")); fracaseference <string> wr = new frActReference <String> (new String ("World"));Qual dessas três frases tornará um objeto de string reciclável? A frase 2 e 3 e a sentença 2 determinarão o objeto String como um objeto reciclável quando houver memória insuficiente e, na terceira frase, o objeto String será determinado como um objeto reciclável em qualquer caso.
Por fim, vamos resumir as situações comuns em que os objetos são julgados como objetos recicláveis que geralmente são encontrados:
1) Exibir o valor de uma referência a NULL ou apontar a referência que já apontou para um objeto para um novo objeto, como o seguinte código:
Objeto obj = new object (); obj = null; objeto obj1 = new object (); objeto obj2 = new Object (); obj1 = obj2;
2) Referência local ao objeto apontado, como o seguinte código:
void fun () {...... para (int i = 0; i <10; i ++) {objeto obj = new Object (); System.out.println (obj.getclass ()); }}Toda vez que o loop é executado, o objeto gerado se tornará um objeto reciclável.
3) Somente referências fracas estão associadas a objetos, como:
FrawReference <String> wr = new frActReference <String> (new String ("World"));2. Algoritmo típico de coleta de lixo
Depois de determinar qual lixo pode ser reciclado, o coletor de lixo precisa fazer é iniciar a coleta de lixo, mas um problema envolvido é: como coletar eficientemente o lixo. Como a especificação Java Virtual Machine não faz regulamentos claros sobre como implementar um coletor de lixo, as máquinas virtuais de cada fabricante podem implementar um coletor de lixo de maneiras diferentes, apenas as idéias principais de vários algoritmos de coleta de lixo comuns são discutidos aqui.
1. Algoritmo de Weep-Weep (Mark-Clear)
Este é o algoritmo de coleta de lixo mais básico. A razão pela qual se diz ser a mais básica é que é a mais fácil de implementar e a idéia mais simples. O algoritmo de limpeza de marcas é dividido em dois estágios: o estágio de marcação e o estágio de limpeza. A tarefa do estágio de marcação é marcar todos os objetos que precisam ser reciclados, e o estágio de limpeza é reciclar o espaço ocupado pelos objetos marcados. O processo específico é mostrado na figura abaixo:
Pode ser facilmente visto a partir da figura que o algoritmo de limpeza de marcas é mais fácil de implementar, mas há um problema sério que é fácil gerar fragmentos de memória. Muitos fragmentos podem causar incapacidade de encontrar espaço suficiente ao alocar espaço para objetos grandes no processo subsequente e desencadear uma nova ação de coleta de lixo com antecedência.
2. Copiar (cópia) Algoritmo
Para resolver as deficiências do algoritmo de varredura de marcas, o algoritmo de cópia foi proposto. Ele divide a memória disponível em dois pedaços de tamanho igual por capacidade, usando apenas uma peça de cada vez. Quando este pedaço de memória for usado, copie o objeto ainda viva para outra peça e limpe o espaço de memória usado de uma só vez, para que os problemas de fragmentação da memória não ocorram. O processo específico é mostrado na figura abaixo:
Embora esse algoritmo seja simples de implementar, eficiente para executar e não é fácil de gerar fragmentação de memória, é caro usar o espaço de memória porque a memória que pode ser usada é reduzida a metade da original.
Obviamente, a eficiência do algoritmo de cópia tem muito a ver com o número de objetos sobreviventes. Se houver muitos objetos sobreviventes, a eficiência do algoritmo de cópia será bastante reduzida.
3.Mark-compacto (colação de marca) Algoritmo
Para resolver as deficiências do algoritmo de cópia e fazer pleno uso do espaço de memória, o algoritmo de compacto de marcas é proposto. O algoritmo marca o mesmo que o mark-sweep, mas depois de concluir a marca, ele não limpa diretamente os objetos recicláveis, mas move todos os objetos vivos para uma extremidade e depois limpa a memória fora do limite final. O processo específico é mostrado na figura abaixo:
4. Algoritmo de coleta geracional
Atualmente, o algoritmo de coleta de geração é usado pela maioria dos coletores de lixo da JVM. Sua idéia principal é dividir a memória em várias regiões diferentes, de acordo com o ciclo de vida da sobrevivência do objeto. De um modo geral, a área da pilha é dividida na antiga geração e na geração jovem. A característica da geração antiga é que apenas um pequeno número de objetos precisa ser reciclado toda vez que o lixo é coletado, enquanto a característica da nova geração é que um grande número de objetos precisa ser reciclado toda vez que o lixo é coletado. Em seguida, o algoritmo de coleta mais adequado pode ser adotado de acordo com as características de diferentes gerações.
Atualmente, a maioria dos coletores de lixo adota o algoritmo de cópia para a nova geração, porque na nova geração, a maioria dos objetos precisa ser reciclada toda vez que a coleta de lixo é coletada, o que significa que o número de operações que precisam ser copiadas é relativamente pequeno, mas, na realidade, o espaço da nova geração não é dividido de acordo com uma ratio de 1: 1. De um modo geral, a nova geração é dividida em um espaço maior e dois espaços de sobrevivência menores. Cada vez que o espaço do Éden e um dos espaços sobreviventes são usados, quando reciclados, os objetos ainda survadores no Éden e o sobrevivente são copiados para outro espaço de sobrevivente e, em seguida, o Éden e os espaços sobreviventes que acabam de ser utilizados são limpos.
Como a velhice é que apenas um pequeno número de objetos é reciclado toda vez, o algoritmo de compacto de marca é geralmente usado.
Observe que há outra geração fora da área da pilha, que é a geração permanente, usada para armazenar aulas, constantes, descrições de métodos etc. A reciclagem de geração permanente recicla principalmente duas partes: constantes descartados e classes inúteis.
3. Coletor típico de lixo
O algoritmo de coleta de lixo é a base teórica da reciclagem de memória, e o coletor de lixo é a implementação específica da reciclagem de memória. A seguir, é apresentada uma descrição de vários coletores de lixo fornecidos pelo Hotspot (JDK 7) MACHERET VIRTUAL. Os usuários podem combinar colecionadores usados em cada época de acordo com suas próprias necessidades.
1. Série/serial antigo
O colecionador serial/serial antigo é o colecionador mais básico e mais antigo. É um único coletor de thread e deve pausar todos os threads do usuário quando ele faz coleta de lixo. O colecionador em série é um colecionador para a nova geração, usando o algoritmo de cópia, e o colecionador em série é um colecionador para a geração antiga, usando o algoritmo Mark-Compact. Sua vantagem é que é simples e eficiente, mas sua desvantagem é que isso causará pausas aos usuários.
2.Parnew
O Parnew Collector é uma versão multithread do colecionador serial que usa vários threads para coleta de lixo.
3. Vasculha paralela
O coletor de eliminação paralela é uma nova geração de colecionadores multithread (colecionadores paralelos). Ele não precisa pausar outros threads de usuário durante a reciclagem. Ele usa o algoritmo de cópia. Este colecionador é diferente dos dois primeiros colecionadores. É principalmente para obter uma taxa de transferência controlada.
4. Paralelo antigo
O antigo paralelo é uma versão antiga do coletor de eliminação paralela (colecionador paralelo) usando algoritmos multithreading e com compacto de marcas.
5.Cms
O coletor CMS (Current Sweep Sweep) é um colecionador destinado a obter o tempo de pausa de recuperação mais curto. É um colecionador simultâneo que usa o algoritmo de varredura de marcas.
6.G1
O colecionador G1 é a conquista mais avançada no desenvolvimento de tecnologia de coletores de hoje. É um colecionador para aplicativos do lado do servidor que podem fazer pleno uso de ambientes multi-CPU e multi-core. Portanto, é um coletor paralelo e de simultaneidade e pode construir um modelo de tempo de pausa previsível.
Aqui estão algumas coisas sobre a alocação de memória:
Em uma direção geral, a alocação de memória de objetos é alocada na pilha. Os objetos são alocados principalmente na nova geração do espaço do Éden e no espaço e, em casos raros, serão alocados diretamente na velhice. Se o espaço da nova geração do espaço do Éden e do espaço for insuficiente, um GC será iniciado. Se o GC for realizado, o espaço do Éden e do espaço podem acomodar o objeto e são colocados no espaço do Éden e no espaço.
Durante o processo GC, os objetos sobreviventes no espaço do Éden e do espaço serão movidos para o espaço, e depois o espaço do Éden e do espaço serão limpos. Se o espaço não puder ser suficiente para armazenar um objeto durante a limpeza, ele moverá o objeto para a velhice. Após o GC, o espaço do Éden e o espaço são usados. Na próxima vez que você GC, o objeto sobrevivente será copiado do espaço e o loop será repetido. Quando um objeto escapa ao GC uma vez na área de sobrevivência, a idade de seu objeto será aumentada em 1. Por padrão, se o objeto atingir 15 anos, ele passará para a meia -idade da velhice.
De um modo geral, objetos grandes serão alocados diretamente para a velhice. Os chamados objetos grandes se referem a objetos que exigem uma grande quantidade de espaço de armazenamento contínuo. O tipo mais comum de objetos grandes são matrizes grandes, como:
byte [] dados = novo byte [4*1024*1024]
Esse tipo de espaço de armazenamento geralmente será alocado diretamente em idosos.
Obviamente, as regras de alocação não são 100% fixas, o que depende de que tipo de combinação de coletores de lixo e os parâmetros relevantes da JVM estão sendo usados atualmente.
O exposto acima é todo o conteúdo deste artigo. Espero que seja útil para o aprendizado de todos e espero que todos apoiem mais o wulin.com.