1 pontos por GN⁺ 2024-11-12 | 1 comentários | Compartilhar no WhatsApp
  • Uma série contínua de miniposts que divide o conhecimento interno da JVM em pequenas unidades, com cada texto focado em um tema, teste, benchmark ou observação
  • Cada post busca ser lido em 5 a 10 minutos e parte do pressuposto de que os elementos da JVM interagem entre si
  • As evidências e discussões podem ser anedóticas, e talvez não tenham passado por revisão suficiente de erros, consistência, estilo, gramática ou duplicações; portanto, é preciso cautela antes de confiar nelas diretamente
  • O conjunto completo é oferecido em ePUB, MOBI e PDF; o PDF tem dezenas de MB por causa da conversão de alta qualidade
  • O índice de textos individuais é dividido nos eixos Compiler, Runtime, GC e Library, abordando temas internos da JVM como otimização de locks, TLAB, pausas de GC, String.intern(), safepoint, referências comprimidas e movimentos condicionais

Premissas ao ler a série

  • JVM Anatomy Quarks é uma série contínua de miniposts que organiza conhecimentos básicos da JVM em textos curtos
  • Cada post aprofunda um único tema, teste, benchmark ou observação
  • Ao ler um post isoladamente, pode faltar contexto, e a maioria dos elementos tratados interage facilmente entre si
  • As evidências e discussões dos textos podem ser anedóticas, e talvez não tenham sido revisadas o suficiente quanto a erros, consistência, estilo, gramática, significado ou duplicações
  • Ao usar ou confiar no conteúdo, o leitor deve assumir o risco por conta própria

Arquivos do conjunto e estrutura do índice

  • O conjunto completo da série é oferecido em três formatos
    • ePUB é o menor, com menos de 1 MB, e é baseado em conversão HTML para ePUB via Pandoc
    • MOBI é pequeno, na faixa de MB, e é baseado em conversão ePUB para MOBI via KindleGen
    • PDF é muito grande, na faixa de dezenas de MB, e é uma saída de alta qualidade baseada em conversão HTML para PDF via wkhtmltopdf
  • O índice individual é organizado nas categorias Compiler, Runtime, GC e Library

Lista de textos por tema

  • Itens com foco em Compiler

    • #1: Lock Coarsening and Loops
    • #14: Constant Variables
    • #15: Just-In-Time Constants
    • #16: Megamorphic Virtual Calls
    • #17: Trust Non-Static Final Fields
    • #18: Scalar Replacement
    • #19: Lock Elision
    • #20: FPU Spills
    • #25: Implicit Null Checks
    • #27: Compiler Blackholes
    • #28: Frequency-Based Code Layout
    • #29: Uncommon Traps
    • #30: Conditional Moves
  • Itens que envolvem Runtime e GC

    • Textos que tratam do comportamento de memória e pausas durante a execução da JVM
    • #2: Transparent Huge Pages
    • #4: TLAB Allocation
    • #5: TLABs and Heap Parsability
    • #6: New Object Stages
    • #7: Object Initialization Costs
    • #9: JNI Critical and GC Locker
    • #22: Safepoint Polls
  • Itens com foco em GC

    • Tratam principalmente de projeto de coletores e comportamento do heap
    • #3: GC Design and Pauses
    • #11: Moving GC and Locality
    • #13: Intergenerational Barriers
    • #21: Heap Uncommit
  • Itens com foco em Runtime

    • Textos sobre o ambiente de execução da JVM e representação de objetos
    • #12: Native Memory Tracking
    • #23: Compressed References
    • #24: Object Alignment
    • #26: Identity Hash Code
  • Itens de Library ou de classificação composta

    • Entre os itens que incluem Library está #10: String.intern()
    • Entre os itens marcados como Compiler e Runtime ao mesmo tempo estão #16, #25, #29 e #30

1 comentários

 
GN⁺ 2024-11-12
Comentários do Hacker News
  • https://shipilev.net/jvm/anatomy-quarks/17-trust-nonstatic-f... é um caso realmente lamentável
    Como alguns frameworks abusaram de JNI e reflexão para alterar campos final que originalmente deveriam ser imutáveis, o código dos usuários acaba perdendo otimizações importantes que só são possíveis para classes fornecidas pelo sistema
    A plataforma, especialmente o compilador e o runtime, precisa impor restrições semânticas de forma muito rigorosa para preservar margem para otimizações futuras

    • Estamos mudando isso como parte da nossa estratégia de integrity by default [1], e um JEP relacionado deve sair em breve
      Na prática, não há muito código que realmente precise alterar final, e mesmo hoje essa operação é limitada a classes dentro do próprio módulo ou a classes explicitamente open; portanto, daqui para frente, a aplicação terá que conceder permissão ao módulo que quiser alterar final
      É parecido com a abordagem que aplicamos recentemente a chamadas nativas e a acesso inseguro à memória
      [1]: https://openjdk.org/jeps/8305968
    • Fico pensando se parte disso não foi um “pecado original” criado por gente seguindo Effective Java cegamente, no estilo coloque final em tudo
      Por causa disso, hoje não dá para mockar facilmente classes final em testes, e as ferramentas de mock chegam a fazer manipulação de bytecode para mockar classes final
      Por exemplo, dentro do Google, Effective Java é requisito, então até a API pública do GDrive tem classes final, justamente uma API externa que é o tipo de coisa que você quer mockar
    • O caso de System.out é um problema do próprio Java
      https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.htm...
      Com esse precedente, não surpreende que outros tenham considerado isso uma prática aceitável
    • Modificadores de campo são restrições semânticas, não restrições de segurança
      Faz sentido que seja possível contorná-los passando por um procedimento adequado de bypass
      O ponto central é a segurança operacional, porque alterar algo que não é modificável pode causar um SEGV, e é exatamente essa a preocupação que os modificadores de acesso tentam tratar
    • Admito que, muito tempo atrás, em uma biblioteca interna que já desapareceu, eu mesmo escrevi três linhas maliciosas de código para tirar o final de um membro, alterá-lo e depois fazê-lo parecer final de novo, só para evitar uma refatoração complicada
      Eu gostaria que isso tivesse sido impedido, mas havia uma necessidade de negócio
  • Mudando um pouco de assunto, a Apple lançou uma nova ponte Swift-Java, e ela é bem legal
    Ela dá suporte tanto a JNI quanto a Panama, e na semana passada eu estava fazendo o port disso para Android
    https://github.com/swiftlang/swift-java

    • Se dá para chamar isso de “moderno”, a abordagem multiplataforma atual é interessante
      A interoperabilidade entre linguagens permite compartilhar uma única biblioteca entre várias plataformas quando faz sentido
      Até agora isso era feito só com C++, adicionando uma API em C quando necessário, mas quando C++ em si não é necessário, obviamente não é a linguagem preferida
      Ainda assim, me preocupo com o custo. Se Swift puder chamar facilmente bibliotecas Kotlin em apps móveis, parece que o app iOS teria que carregar algo parecido com uma JVM de alguma forma; e, no sentido inverso, se um app Android chamar Swift, imagino que ele carregue o runtime do Swift
      No fim, há overhead
      Tenho receio de que um dia vire comum desenvolvedores dependerem de uma biblioteca Swift, que depende de uma biblioteca Kotlin, que sobe uma JVM e depois chama C++ via JNI
      Isso lembra a situação dos gerenciadores de pacotes modernos: mesmo com poucas dependências diretas, por ser “fácil demais para se preocupar”, o programa acaba rapidamente com mais de 100 dependências transitivas
  • Fico feliz que esta ótima coletânea de textos tenha sido compartilhada aqui. Aprendi muito sobre a JVM acompanhando esta série
    Gosto especialmente deste artigo sobre como a expressão comumente chamada de “alocação na stack” em Java está errada: https://shipilev.net/jvm/anatomy-quarks/18-scalar-replacemen...
    O que a JVM realmente faz é análise de escape + substituição escalar

  • Gosto da extensão destes textos
    Dá para ler um deles de ponta a ponta em poucos minutos e, se quiser, rodar o benchmark localmente

  • Se você trabalhou por alguns anos com linguagens baseadas na JVM, esta coletânea é realmente interessante
    Ainda me lembro de quando comecei a lê-la alguns anos atrás

  • Alguém sabe por que o nome desta série mudou de “JVM Anatomy Park”?

    • Pelo que parece, o nome foi alterado quando começaram a vir à tona informações sobre o comportamento online de Justin Rolland
  • Acabei praticamente esquecendo Java
    Não me passa pela cabeça começar um novo projeto em Java
    Se eu precisar de desenvolvimento rápido e flexibilidade, escolheria Python; se quiser lidar com muita concorrência de entrada/saída com garbage collection, Go; se precisar de uma linguagem compilada boa e equilibrada, Swift; se for uma linguagem compilada que exija desempenho e segurança, Rust
    É só preferência pessoal, e sei que Kotlin tornou Java mais agradável de usar, mas ainda assim é essa a sensação

    • Imagino que eu não seja o único, mas talvez seja apenas uma situação em que Java não é necessário
      Os principais pontos fortes de Java são: há um número quase infinito de desenvolvedores com experiência em Java, um enorme conjunto de bibliotecas existentes, muitas delas voltadas ao enterprise, é fácil gerenciar bases de código muito grandes com muitos contribuidores, e a VM padrão, desenvolvida ao longo de décadas, é muito robusta, bastante rápida e suportada em praticamente todas as plataformas
      Ela não tem a dominância esmagadora que tinha no início dos anos 2000, nem mesmo no enterprise, e é uma típica linguagem “blub”, mas, se você prevê escala enterprise e escalar com muitos desenvolvedores é mais importante do que desempenho puro, continua sendo uma escolha perfeitamente razoável
      Eu gosto de Rust, mas quem paga minhas contas é Java
    • Complementando outras respostas, Java também tem características suficientes para startups, então faz sentido usá-la em novos projetos
      Com frameworks modernos e assistência de IA, dá para colocar um backend decente no ar em poucos dias
      Se você é um cofundador técnico solo, para criar um MVP rapidamente basta conhecer Java ou Kotlin e alguma stack de frontend; na prática, você vai gastar muito mais tempo em tarefas fora de codificação, então as diferenças de recursos entre linguagens importam menos
      Se for para mobile nativo, Swift pode ser a segunda linguagem
      Além disso, por um bom tempo é bem provável que escalabilidade não seja o primeiro problema. A expansão da equipe vem antes, e gargalos de desempenho provavelmente só aparecerão muito depois
      Java é adequada para equipes grandes
      Do ponto de vista de negócios, se você quer um pool de talentos maior, ciclos de entrega rápidos e algo que possa continuar sendo a stack principal no longo prazo, Java ou Kotlin provavelmente são a melhor escolha
      Se quiser usar uma tecnologia bacana como benefício para atrair um certo perfil de desenvolvedor, ou se tiver um caso de negócio raro, pode escolher Go ou Rust
      Python é popular na academia e em bootcamps, mas, sinceramente, não sei bem qual é seu valor de negócio em backends de uso geral
    • Sobre a JVM há muitas linguagens muito agradáveis de usar, como Clojure
      Eu não descartaria a JVM como um todo. A JVM é uma obra-prima de engenharia e vem evoluindo rapidamente hoje em dia. Basta olhar para Loom, Panama, Leyden etc.
    • Para responder de forma incendiária a um comentário incendiário: Java é melhor que Go em todos os aspectos, e 90% de quase todos os casos que você citou podem ser resolvidos com Java
      Por isso, para quase tudo, Java é uma escolha bastante claramente boa
    • Você provavelmente não é o único, mas nem todo mundo pensa assim
      Kotlin com Java 21+ é minha combinação de primeira escolha para serviços centrados em entrada/saída ou praticamente qualquer tipo de serviço
      É realmente confortável de usar e, graças às threads virtuais, permite código tão simples e eficiente quanto Go, ao mesmo tempo em que aproveita um dos maiores e melhores ecossistemas de bibliotecas do mundo
      Não estou tentando diminuir Go ou Python. Se são suas ferramentas preferidas, tudo bem
      Mas Java não se tornou tão irrelevante quanto você imagina