Como o Java 7 vai usar a nova coleta de lixo G1 por padrão, o Java será capaz de lidar com uma ordem de magnitude maior sem tempos de pausa de GC supostamente "devastadores"? Alguém já implementou o G1 na produção, quais foram suas experiências?
Para ser justo, a única vez que vi pausas de GC realmente longas foi em heaps muito grandes, muito mais do que uma estação de trabalho teria. Para esclarecer minha pergunta; O G1 abrirá o portal para pilhas na casa das centenas de GB? TB?
java
garbage-collection
java-7
g1gc
Benstpierre
fonte
fonte
Respostas:
Parece que o objetivo do G1 é ter tempos de pausa menores, até o ponto em que tenha a capacidade de especificar um objetivo de tempo máximo de pausa.
A coleta de lixo não é mais apenas um negócio simples de "Ei, está cheio, vamos mover tudo de uma vez e começar de novo" - é um sistema de encadeamento em segundo plano incrivelmente complexo, de vários níveis. Ele pode fazer grande parte de sua manutenção em segundo plano, sem nenhuma pausa, e também usa o conhecimento dos padrões esperados do sistema em tempo de execução para ajudar - como assumir que a maioria dos objetos morre logo após serem criados, etc.
Eu diria que os tempos de pausa do GC continuarão a melhorar, e não piorar, com versões futuras.
EDITAR:
ao reler, ocorreu-me que uso Java diariamente - Eclipse, Azureus e os aplicativos que desenvolvo, e já faz MUITO TEMPO desde que vi uma pausa. Não é uma pausa significativa, mas quero dizer qualquer pausa.
Já vi pausas quando clico com o botão direito do mouse no Windows Explorer ou (ocasionalmente) quando conecto determinados hardwares USB, mas com Java --- nenhum.
O GC ainda é um problema para alguém?
fonte
Tenho testado com um aplicativo pesado: 60-70 GB alocados para heap, com 20-50 GB em uso a qualquer momento. Com esses tipos de aplicativos, é um eufemismo dizer que sua milhagem pode variar. Estou executando o JDK 1.6_22 no Linux. As versões secundárias são importantes - antes de cerca de 1.6_20, havia erros no G1 que causavam NullPointerExceptions aleatórios.
Descobri que é muito bom manter a meta de pausa que você atribui na maior parte do tempo. O padrão parece ser uma pausa de 100 ms (0,1 segundo), e venho dizendo para ele fazer a metade disso (-XX: MaxGCPauseMillis = 50). No entanto, quando fica realmente com pouca memória, ele entra em pânico e faz uma coleta de lixo completa para o mundo inteiro. Com 65 GB, isso leva entre 30 segundos e 2 minutos. (O número de CPUs provavelmente não faz diferença; provavelmente é limitado pela velocidade do barramento.)
Comparado com o CMS (que não é o servidor GC padrão, mas deveria ser para servidores da web e outros aplicativos em tempo real), as pausas típicas são muito mais previsíveis e podem ser muito mais curtas. Até agora estou tendo mais sorte com o CMS para as grandes pausas, mas isso pode ser aleatório; Estou vendo-os apenas algumas vezes a cada 24 horas. Não tenho certeza de qual será o mais adequado no meu ambiente de produção no momento, mas provavelmente G1. Se a Oracle continuar ajustando, eu suspeito que G1 acabará sendo o vencedor.
Se você não está tendo problemas com os coletores de lixo existentes, não há razão para considerar o G1 agora. Se você estiver executando um aplicativo de baixa latência, como um aplicativo GUI, G1 é provavelmente a escolha certa, com MaxGCPauseMillis definido muito baixo. Se você está executando um aplicativo em lote, G1 não compra nada.
fonte
Embora eu não tenha testado o G1 em produção, pensei em comentar que os GCs já são problemáticos para casos sem pilhas "gigantescas". Especificamente, serviços com apenas, digamos, 2 ou 4 GB podem ser severamente afetados pelo GC. Os GCs de geração jovem geralmente não são problemáticos, pois terminam em milissegundos de um dígito (ou no máximo dois dígitos). Mas as coleções da velha geração são muito mais problemáticas, pois levam vários segundos com tamanhos da velha geração de 1 GB ou mais.
Agora: em teoria o CMS pode ajudar muito nisso, pois pode executar grande parte de sua operação simultaneamente. No entanto, com o tempo, haverá casos em que ele não poderá fazer isso e terá que voltar para a coleta "parar o mundo". E quando isso acontecer (depois de, digamos, 1 hora - não com frequência, mas ainda com muita frequência), bem, segure a porra do chapéu. Isso pode levar um minuto ou mais. Isso é especialmente problemático para serviços que tentam limitar a latência máxima; em vez de levar, digamos, 25 milissegundos para atender a uma solicitação, agora leva dez segundos ou mais. Adicionar injuria aos clientes insultuosos, muitas vezes, expira o pedido e tenta novamente, levando a mais problemas (também conhecido como "tempestade de merda").
Essa é uma área em que o G1 esperava ajudar muito. Trabalhei para uma grande empresa que oferece serviços em nuvem para armazenamento e envio de mensagens; e não podíamos usar o CMS porque, embora na maior parte do tempo funcionasse melhor do que as variedades paralelas, apresentava esses colapsos. Então, por cerca de uma hora as coisas estavam boas; e então as coisas caíram no ventilador ... e como o serviço era baseado em clusters, quando um nó tinha problemas, outros normalmente o seguiam (já que os tempos limite induzidos por GC levam a outros nós acreditam que o nó havia travado, levando a redirecionamentos).
Não acho que GC seja um grande problema para aplicativos, e talvez até serviços não agrupados sejam afetados com menos frequência. Porém, mais e mais sistemas são agrupados (especialmente graças aos armazenamentos de dados NoSQL) e os tamanhos de heap estão crescendo. Os GCs OldGen são superlinearmente relacionados ao tamanho do heap (o que significa que dobrar o tamanho do heap mais do que duplica o tempo do GC, assumindo que o tamanho do conjunto de dados ativo também dobra).
fonte
O CTO da Azul, Gil Tene, tem uma boa visão geral dos problemas associados à coleta de lixo e uma revisão de várias soluções em sua apresentação Entendendo a coleta de lixo do Java e o que você pode fazer sobre ela , e há detalhes adicionais neste artigo: http: // www.infoq.com/articles/azul_gc_in_detail .
O Coletor de Lixo C4 da Azul em nossa JVM Zing é paralelo e simultâneo e usa o mesmo mecanismo de GC para a nova e velha geração, trabalhando simultaneamente e compactando em ambos os casos. Mais importante ainda, o C4 não tem um retrocesso que impede o mundo. Toda compactação é executada simultaneamente com o aplicativo em execução. Temos clientes executando muito grandes (centenas de GBytes) com tempos de pausa de GC de pior caso de <10 mseg e, dependendo do aplicativo, muitas vezes menos de 1-2 mseg.
O problema com CMS e G1 é que em algum ponto a memória heap Java deve ser compactada e ambos os coletores de lixo param o mundo / STW (ou seja, pausam o aplicativo) para realizar a compactação. Portanto, embora o CMS e o G1 possam aumentar as pausas STW, eles não as eliminam. O C4 da Azul, no entanto, elimina completamente as pausas STW e é por isso que Zing tem pausas de GC tão baixas, mesmo para tamanhos de heap gigantescos.
E para corrigir uma afirmação feita em uma resposta anterior, o Zing não exige nenhuma alteração no sistema operacional. Ele funciona como qualquer outra JVM em distros Linux não modificadas.
fonte
Já estamos usando o G1GC, há quase dois anos. Está indo muito bem em nosso sistema de processamento de transações de missão crítica e provou ser um ótimo suporte para alto rendimento, poucas pausas, simultaneidade e gerenciamento otimizado de memória pesada.
Estamos usando as seguintes configurações de JVM:
Atualizada
fonte
O coletor G1 reduz o impacto de coleções completas. Se você tiver um aplicativo em que já reduziu a necessidade de coletas completas, o coletor de varredura de mapa simultâneo é tão bom e, em minha experiência, tem tempos menores de coleta menores.
fonte
Parece que o G1 que inicia o JDK7u4 finalmente é oficialmente suportado, consulte o RN para JDK7u4 http://www.oracle.com/technetwork/java/javase/7u4-relnotes-1575007.html .
Em nossos testes ainda para grandes JVMs, o CMS ajustado ainda funciona melhor do que o G1, mas acho que vai crescer melhor.
fonte
Recentemente, fui transferido de
CMS para G1GC com heap 4G e processador de 8 núcleos em servidores com JDK 1.7.45 .
(JDK 1.8.x G1GC é preferível a 1.7, mas devido a algumas limitações, tenho que me ater à versão 1.7.45)
Eu configurei os parâmetros-chave abaixo e mantive todos os outros parâmetros com os valores padrão.
Se você quiser ajustar esses parâmetros, dê uma olhada neste artigo do oracle .
Observações principais:
Mas ainda estou feliz que o tempo de pausa Max GC é menor do que no CMS. Eu defini o tempo máximo de pausa do GC como 1,5 segundos e este valor ainda não foi ultrapassado.
Pergunta relacionada de SE:
Coleta de lixo Java 7 (JDK 7) e documentação no G1
fonte
O CMS pode levar a uma degradação lenta do desempenho, mesmo se você o estiver executando sem acumular objetos titulados. Isso ocorre por causa da fragmentação da memória que G1 supostamente evita.
O mito do G1 disponível apenas com suporte pago é apenas isso, um mito. A Sun e agora a Oracle esclareceram isso na página JDK.
fonte
O G1 GC deve funcionar melhor. Mas se definir -XX: MaxGCPauseMill for muito agressivo, o lixo será coletado muito lentamente. E é por isso que o GC completo foi acionado no exemplo de David Leppik.
fonte
Acabei de implementar o G1 Garbage Collector em nosso projeto Terracotta Big Memory. Trabalhando em diferentes tipos de coletores, G1 nos deu os melhores resultados com menos de 600ms de tempo de resposta.
Você pode encontrar os resultados do teste (26 no total) aqui
Espero que ajude.
fonte
Migrei recentemente parte do Twicsy para um novo servidor com 128 GB de RAM e decidi usar 1.7. Comecei usando todas as mesmas configurações de memória que usei no 1.6 (tenho várias instâncias executando fazendo várias coisas, em qualquer lugar de 500 MB de heap até 15 GB, e agora um novo com 40 GB) e isso não funcionou bem . 1.7 parece usar mais heap do que 1.6 e tive muitos problemas nos primeiros dias. Felizmente, eu tinha bastante RAM para trabalhar e aumentei a RAM para a maioria dos meus processos, mas ainda estava tendo alguns problemas. Meu MO normal era usar um tamanho de heap mínimo muito pequeno de 16 m, mesmo com um heap máximo de vários gigabytes, e então ligar o GC incremental. Isso manteve as pausas mínimas. Isso não funciona agora, e eu tive que aumentar o tamanho mínimo para o que eu esperava usar em média na pilha, e isso funcionou muito bem. Ainda tenho o GC incremental ativado, mas tentarei sem ele. Sem nenhuma pausa agora, e as coisas parecem estar correndo muito rápido. Então, acho que a moral da história é não esperar que suas configurações de memória sejam traduzidas perfeitamente de 1.6 para 1.7.
fonte
G1 torna o aplicativo muito mais ágil: a latência do aplicativo aumentará - o aplicativo pode ser chamado de "soft-real-time". Isso é feito substituindo-se dois tipos de execuções de GC (pequenas, menores e uma grande na Geração Tenured) por outras de tamanho igual.
Para mais detalhes veja isto: http://geekroom.de/java/java-expertise-g1-fur-java-7/
fonte
Estou trabalhando com Java, para Heap pequeno e grande, e a questão do GC e do GC Completo aparece todos os dias, pois as restrições podem ser mais rígidas do que outras: em determinado ambiente, 0,1 segundo de GC scavenger ou GC Completo, kill simplesmente a fonctionnalité, e ter configuração granulada fina e capacidade é importante (CMS, iCMS, outros ... o objetivo está aqui para ter o melhor tempo de resposta possível com o tratamento quase em tempo real (aqui o tratamento em tempo real é frequentemente de 25 ms) , portanto, basicamente, quaisquer melhorias na ergonomia e heuristique do GC são bem-vindas!
fonte
Eu uso G1GC no Java 8 e também com Groovy (também Java 8), e estou fazendo vários tipos de cargas de trabalho e, em geral, G1GC funciona assim:
O uso de memória é muito baixo, por exemplo, 100 MB em vez de 500 MB em comparação com as configurações padrão do Java
O tempo de resposta é consistente e muito baixo
O desempenho entre as configurações padrão e G1GC é 20% mais lento ao usar G1GC no pior cenário (sem ajuste, aplicativo de thread único). Não é muito considerando o bom tempo de resposta e o baixo uso de memória.
Ao executar a partir do Tomcat, que é multithread, o desempenho geral é 30% melhor e o uso de memória é muito menor, assim como os tempos de resposta são muito menores.
Portanto, em geral, ao usar cargas de trabalho realmente diversas, G1GC é um coletor muito bom para Java 8 para aplicativos multi-threaded e, mesmo para single-threaded, há alguns benefícios.
fonte
Não é sugerido usar java8 com G1GC para cálculo de ponto flutuante com JVM semelhante a ponto de acesso. É perigoso para a integridade e precisão do aplicativo.
https://bugs.openjdk.java.net/browse/JDK-8148175
JDK-8165766
JDK-8186112
fonte