<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Victor Hugo</title>
    <description>The latest articles on Forem by Victor Hugo (@shyvictor).</description>
    <link>https://forem.com/shyvictor</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1170005%2Fcd1e9b91-af4e-4ba4-bf7a-20584f51dff6.png</url>
      <title>Forem: Victor Hugo</title>
      <link>https://forem.com/shyvictor</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/shyvictor"/>
    <language>en</language>
    <item>
      <title>Java Virtual Machine: ciclo de vida e Class Loaders</title>
      <dc:creator>Victor Hugo</dc:creator>
      <pubDate>Mon, 14 Oct 2024 12:03:56 +0000</pubDate>
      <link>https://forem.com/shyvictor/java-virtual-machine-ciclo-de-vida-e-class-loaders-1ki6</link>
      <guid>https://forem.com/shyvictor/java-virtual-machine-ciclo-de-vida-e-class-loaders-1ki6</guid>
      <description>&lt;p&gt;A Java Virtual Machine (JVM) é o núcleo do ecossistema Java, fornecendo todas as ferramentas essenciais para a execução de código Java. Para compreender plenamente seu funcionamento, é crucial entender o ciclo de vida desse interpretador e as suas implicações para o desempenho e otimização de aplicações Java. &lt;/p&gt;

&lt;p&gt;Todo o ciclo de vida da JVM inicia-se com um processo fundamental chamado de "JVM Bootstrapping" que é responsável por construir todo o ambiente de execução e prepará-lo. É nesse contexto que: os argumentos passados na linha de comando são interpretados, o código da JVM é alocado na memória, as estruturas de dados internas da JVM são inicializadas, o gerenciamento de memória se inicia, e por fim a principal thread da aplicação passa a operar. Vamos explorar cada subprocesso descrito nesse parágrafo individualmente:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Os argumentos passados na linha de comando são interpretados&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Quando se inicia o programa através da linha de comando, a JVM inicia uma cadeia de processos responsáveis por analisar os argumentos fornecidos, os quais podem incluir parâmetros de inicialização — como por exemplo: -Xms e -Xmx para definir o tamanho mínimo e máximo do heap, área da memória responsável pela alocação e criação de objetos no contexto da aplicação — especificações de debug ou configurações até mesmo do próprio ciclo do Garbage Collector. &lt;/p&gt;

&lt;p&gt;Antes de prosseguir, é importante mencionar: com o intuito de simplificação, estaremos analisando o segmento do código que lida com o parsing de argumentos avançados da JVM — os que se iniciam com -XX. &lt;/p&gt;

&lt;p&gt;Para se ter mais clareza, vamos utilizar o código open-source da OpenJDK para mais referências. No arquivo &lt;strong&gt;arguments.cpp&lt;/strong&gt; localizado no diretório &lt;strong&gt;src/hotspot/share/runtime.arguments.cpp&lt;/strong&gt; a função que interpreta parâmetros avançados (-XX) pelo CLI é essa:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5dyvh0s2b7imgyb6ovq4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5dyvh0s2b7imgyb6ovq4.png" alt="Image description" width="523" height="18"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fazendo uma breve análise, a função inicia uma verificação para ver se o argumento passado se inicia com + ou -, determinando se a flag for booleana, e também se deve ser desativada ou ativada.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F559ljk28uad8wm6w18yh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F559ljk28uad8wm6w18yh.png" alt="Image description" width="532" height="199"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Depois disso, o código começa a extração do nome da flag. Cada caractere é analisado, se não for alfanumerico ou não for _, ele termina (significando que o nome da flag está completa).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F61grql35913usipnnkku.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F61grql35913usipnnkku.png" alt="Image description" width="262" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Depois de fazer as verificações e identificar o nome da flag, o método &lt;strong&gt;JVMFlag* flag = find_jvm_flag(name, name_len);&lt;/strong&gt; finalmente é invocado para ver se há alguma configuração disponível ao que foi fornecido.&lt;/p&gt;

&lt;p&gt;Esse é um pequeno resumo de como os argumentos mais avançados da -XX são parseados. É possível encontrar, no entanto, nesse mesmo arquivo que irei citar, os processos de argumentos que se iniciam com -X que passam por outra função de parsing:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq6hevbx38k528pest5fp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq6hevbx38k528pest5fp.png" alt="Image description" width="800" height="35"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Exemplo da flag: -XMS&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faye4ec6e2dbbxbrfsmm6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Faye4ec6e2dbbxbrfsmm6.png" alt="Image description" width="549" height="234"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ARTIGO EM CONSTRUÇÃO&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>jvm</category>
      <category>classloader</category>
      <category>internal</category>
    </item>
    <item>
      <title>Explorando as profundezas da JVM: -XX:+PrintCompilation</title>
      <dc:creator>Victor Hugo</dc:creator>
      <pubDate>Tue, 26 Sep 2023 22:17:01 +0000</pubDate>
      <link>https://forem.com/shyvictor/explorando-as-profundezas-da-jvm-xxprintcompilation-5ak9</link>
      <guid>https://forem.com/shyvictor/explorando-as-profundezas-da-jvm-xxprintcompilation-5ak9</guid>
      <description>&lt;p&gt;Não é segredo para ninguém que A Máquina Virtual Java, ou JVM (Java Virtual Machine), é uma parte fundamental do ecossistema da linguagem de programação Java. Ela foi revolucionária em sua época, trazendo inovações que transformaram a forma como o software é desenvolvido, executado e distribuído. A JVM é uma máquina virtual que permite que os programas Java sejam executados em diferentes plataformas, proporcionando uma abstração eficiente e independente do sistema operacional subjacente.&lt;/p&gt;

&lt;p&gt;Não se limitando apenas a esse escopo revolucionário, mas a JVM também trouxe revoluções no que diz respeito a performance de código, tendo em vista que a abstração por trás da JVM trouxe consigo um conjunto de ferramentas para impressionar nesse contexto: JIT, Garbage Collection, técnicas de inling, otimização de laços, perfil de desempenho. Hoje falaremos sobre sua incrível capacidade de traçar um perfil durante a execução de um código, analisar trechos de códigos que são frequentemente executados durante o tempo de execução e transformá-los em código nativo de máquina.&lt;/p&gt;

&lt;p&gt;Para uma introdução à especificação da Máquina Virtual Java (JVM), é crucial entender que ela opera intrinsecamente como se fosse um sistema multithread. Isso significa que tanto a interpretação do bytecode quanto a compilação para código nativo ocorrem em threads separadas, de forma simultânea, no contexto da utilização do compilador "Just in Time" (JIT).&lt;/p&gt;

&lt;p&gt;Essa abordagem "multithread" permite que a JVM execute diversas tarefas de forma paralela e otimizada. Enquanto uma thread interpreta o bytecode Java, outra thread compila o código para a forma nativa da máquina. Isso resulta em um desempenho significativamente aprimorado, pois a JVM pode executar código nativo de maneira eficiente e, ao mesmo tempo, manter a portabilidade do código-fonte Java.&lt;/p&gt;

&lt;p&gt;Mas o que é exatamente o JIT? Nesse contexto, dentro da JVM, sua função principal é otimizar a execução de programas Java, convertendo o código Java intermediário (bytecode) em código nativo da máquina durante o tempo de execução. Ele compila as partes mais críticas do código para código nativo da máquina e aplica otimizações específicas para tornar a execução mais rápida e eficiente.&lt;/p&gt;

&lt;p&gt;No entanto, como podemos visualizar, de forma analítica, esse processo, na prática? Nos vamos utilizar uma flag da máquina virtual denominada de : &lt;code&gt;-XX:+PrintCompilation&lt;/code&gt; adicionando ela como argumento no comando de execução &lt;code&gt;java&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Por exemplo:&lt;br&gt;
&lt;code&gt;java &amp;lt;jvm args&amp;gt; &amp;lt;class&amp;gt; &amp;lt;cmd args&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Antes de estudarmos profundamente o que essa analisa nos traz, vamos entender a estrutura dessa flag e o que ela significa conceitualmente:&lt;/p&gt;

&lt;p&gt;-XX significa que é uma opção avançada, o sinal "+" ou "-" basicamente está apontando se queremos que essa opção seja habilitada ou não, e por fim, a última parte é o nome da opção que passamos de argumento para a JVM. Resumidamente, estamos habilitando (+) uma opção avançada (-XX) chamada de PrintCompilation. Importante mencionar e ressaltar que as flags devem obrigatoriamente respeitar letras maiúsculas e minúsculas, com cada letra inicial sendo maiúscula no que diz respeito ao nome da opção.&lt;/p&gt;

&lt;p&gt;Para exemplificar a utilização dessa flag, vamos utilizar o seguinte código, &lt;strong&gt;não otimizado&lt;/strong&gt;, que performa a sequência de Fibonacci até um número inteiro N:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8lH8o8Mh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dkmvtgze98kh4ez73o4v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8lH8o8Mh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dkmvtgze98kh4ez73o4v.png" alt="Image description" width="697" height="442"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No nosso código Main instanciaremos a classe e executaremos da seguinte forma:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wKDCq1Sm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v1cv6wd9tx9zg5n9xrvx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wKDCq1Sm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v1cv6wd9tx9zg5n9xrvx.png" alt="Image description" width="800" height="473"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Caso você esteja usando uma IDE como a minha, configure as opções de execução e adicione a flag da JVM que estamos utilizando. No IntelliJ, isso é feito dessa forma: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--12K4fSPD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t46stgr0b8orgwd2l9y8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--12K4fSPD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t46stgr0b8orgwd2l9y8.png" alt="Image description" width="701" height="167"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Quando executarmos o código, nosso output será composto pelo seguinte:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--m2po417L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g9gc779oa3skfk7pedz7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--m2po417L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/g9gc779oa3skfk7pedz7.png" alt="Image description" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Agora, vamos entender o que é cada coluna e informação presente nessa tela.&lt;/p&gt;

&lt;p&gt;A primeira coluna representa o número de milissegundos desde que a máquina virtual foi iniciada. Por exemplo, na primeira linha da imagem, o primeiro valor da primeira coluna é: 558. Isso quer dizer que se passaram 558ms desde o início da JVM naquela instrução específica.  &lt;/p&gt;

&lt;p&gt;A segunda coluna representa a ordem que o método/instrução/bloco de código foi executado sequencialmente, isto é, em ordem. Na nossa imagem, na primeira linha, aquela instrução foi executada na posição 193, também conhecido como um identificador interno de tarefas.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Observação&lt;/strong&gt;: o fato de algumas partes não aparecerem em ordem seguidas uma das outras é consequência direta do fato que diferentes blocos de código demoram mais para compilar do que os outros. Isso pode decorrer de problemas de multithreading, complexidade ou até mesmo tamanho.&lt;/p&gt;

&lt;p&gt;Note que há um espaço entre a segunda coluna e a próxima, e às vezes ele é preenchido por um símbolo. Eles têm significados:&lt;/p&gt;

&lt;p&gt;O símbolo &lt;strong&gt;%&lt;/strong&gt; faz referência a uma técnica chamada de on-stack replacement &lt;strong&gt;(OSR)&lt;/strong&gt;. Vamos lembrar que o JIT essencialmente falando é um processo assíncrono, então quando um escopo específico do nosso código é se torna uma opção viável para ser compilado em código nativo de máquina, devido a frequência de sua utilização ou relacionados, esse fragmento de escopo é colocado numa fila. Ao invés de esperar a compilação, a máquina virtual vai continuar interpretando o código em sequência, mas na próxima vez que esse escopo que estamos lidando for chamado, a JVM executará ele em sua versão compilada nativamente. Claro que aqui assumimos que a compilação foi finalizada na thread que sustenta essa fila mencionada.  Quando isso acontece, o código estará sendo executado numa parte da memória especial denominada de &lt;strong&gt;code cache&lt;/strong&gt;. Esse símbolo também garante que o escopo está rodando do jeito mais otimizado possível.&lt;/p&gt;

&lt;p&gt;O símbolo &lt;strong&gt;n&lt;/strong&gt; indica que a JVM criou um código compilado para tornar mais fácil a chamada a um método que é implementado em linguagem nativa. O &lt;strong&gt;s&lt;/strong&gt; significa que é um método &lt;strong&gt;synchronized&lt;/strong&gt; e &lt;strong&gt;!&lt;/strong&gt; representa que há tratamento de exceções no escopo referenciado. &lt;/p&gt;

&lt;p&gt;Note que na próxima coluna, o elemento está num padrão que varia de 0 até 4. Basicamente, são os níveis de compilação. No nível &lt;strong&gt;0&lt;/strong&gt; o bloco de código não foi compilado, ele apenas foi interpretado pela máquina virtual. Nos níveis &lt;strong&gt;1&lt;/strong&gt;,&lt;strong&gt;2&lt;/strong&gt;, &lt;strong&gt;3&lt;/strong&gt;, o código foi compilado pelo compilador &lt;strong&gt;C1&lt;/strong&gt; da máquina virtual. O nível &lt;strong&gt;1&lt;/strong&gt; classicamente é o mais otimizado. No nível &lt;strong&gt;4&lt;/strong&gt;, o trecho mencionado foi compilado pelo &lt;strong&gt;C2&lt;/strong&gt; e agora ele está na versão mais alta possível de compilação, sendo ele adicionado no &lt;strong&gt;code cache&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Observação&lt;/strong&gt;: nesse artigo em específico, apenas assuma como verdade que existem dois compiladores, C1 e C2, inerentes a máquina virtual e que eles são responsáveis pelo nível de compilação explicado anteriormente. Uma explicação mais detalhada sobre eles será dada no próximo artigo.&lt;/p&gt;

&lt;p&gt;A próxima coluna é a referência a instrução da linha, e, por fim, mas não menos importante, o último campo é o tamanho em bytes do bytecode.&lt;/p&gt;

&lt;p&gt;Nos próximos artigos nos aventuraremos sobre: &lt;strong&gt;code cache&lt;/strong&gt;, &lt;strong&gt;C1&lt;/strong&gt;, &lt;strong&gt;C2&lt;/strong&gt; e outras idiossincrasias da Máquina Virtual Java.&lt;/p&gt;

</description>
      <category>java</category>
      <category>jvm</category>
      <category>virtualmachine</category>
    </item>
  </channel>
</rss>
