← voltar para guias
AvançadoBack-EndDevOps/Infra

Transformando JARs em binário com GraalVM

Como usar a GraalVM Native Image para compilar JARs Kotlin em binários nativos, eliminando a dependência de JVM e melhorando drasticamente o tempo de execução.

Kotlinautas

Esse conteúdo é oferecido e distribuído pela comunidade Kotlinautas, uma comunidade brasileira que busca oferecer conteúdo gratuito sobre a linguagem Kotlin em um espaço plural.

capa Kotlinautas

O que é um binário?

Binário é um executável do sistema , pode ser rodado diretamente, porque é composto totalmente por linguagem de máquina.

As vantagens são a velocidade de execução, que costuma ser BEM rápida, e o fato de não precisar de nenhuma linguagem instalada pra rodar o programa. O próprio sistema cuida disso.

GraalVM

GraalVM é uma máquina virtual da Oracle para aumentar a velocidade de aplicações. Uma das funções da GraalVM é a Native Images, que é uma maneira de unir código de qualquer linguagem da JVM (Java, Kotlin, Clojure, etc.) em um único arquivo totalmente em código de máquina. Eliminando a necessidade de utilizar uma JVM para rodar um projeto.

Esse processo de transformar código JVM em binário deve ser usado só quando você for colocar em produção. É demorado e consome bastante processamento e memória , então em desenvolvimento, o fluxo normal da JVM é mais prático.

Instalação da GraalVM

Há alguns documentos oficiais de instalação da GraalVM para algumas plataformas, sendo:

Instalação da Native Image

A Native Image pode ser instalada usando a GraalVM Updater, que é uma ferramenta utilizada para instalar utilitários da GraalVM. Essa instalação pode ser feita com o comando:

gu install native-image
Hello World

Agora vamos criar um Hello World em Kotlin para gerar o JAR desse Hello World para transformar em binário com Native Image.

Isso pode ser feito com qualquer editor, não há necessidade de utilizar o IntelliJ, mas caso prefira, crie um projeto no IntelliJ para isso.

Arquivo main.kt:

fun main(){
  println("Olá Mundo!")
  }

Agora precisamos transformar esse arquivo em um JAR. Para isso, podemos usar o kotlinc, que é o compilador do Kotlin. Vá até a pasta onde o arquivo está e rode o comando abaixo:

kotlinc main.kt -include-runtime -d main.jar

Agora temos o nosso JAR no arquivo main.jar. Caso você queira executar esse JAR, isso pode ser feito com o comando java -jar main.kt, que terá Olá Mundo! como resultado:

Olá Mundo!

Agora precisamos transformar esse JAR em binário, podemos fazer isso com o comando native-image. Dessa maneira:

native-image --static -jar main.jar

Com isso o processamento irá começar. A GraalVM ao longo do processamento irá mostrar alguns dados sobre o processo:

$ native-image --static -jar main.jar

Build on Server(pid: 5484, port: 35163)
[main:5484]    classlist:     441.34 ms
[main:5484]        (cap):   1,017.18 ms
[main:5484]        setup:   1,581.26 ms
[main:5484]   (typeflow):   2,216.25 ms
[main:5484]    (objects):     516.04 ms
[main:5484]   (features):      86.21 ms
[main:5484]     analysis:   2,876.19 ms
[main:5484]     universe:     131.56 ms
[main:5484]      (parse):     610.96 ms
[main:5484]     (inline):     518.10 ms
[main:5484]    (compile):   2,818.48 ms
[main:5484]      compile:   4,187.55 ms
[main:5484]        image:     354.83 ms
[main:5484]        write:     164.75 ms
[main:5484]      [total]:   9,769.44 ms

Após o término desse processamento teremos um binário main com todo o código atual. Esse binário terá cerca de 12MB de tamanho.

Para executar esse binário, no Windows podemos usar o comando main no diretório que esse binário está, e em Linux/MacOS podemos usar ./main.

Velocidade

Podemos comparar o tempo de execução do JAR e do binário, caso você esteja em sistemas Linux/MacOS existe o comando time para medir o tempo de execução de um comando, comparando os dois métodos teremos o resultado abaixo:

$ time java -jar main.jar
Olá Mundo!
java -jar main.jar  0,12s user 0,02s system 64% cpu 0,114 total

$ time ./main
Olá Mundo!
./main  0,00s user 0,00s system 74% cpu 0,002 total

Podemos ver que a principal diferença entre os dois é a diferença de tempo que cada um executou. Enquanto java -jar main.jar demorou 0.12 segundos para rodar, ./main levou 0 segundos para rodar, de maneira quase instantânea. Claro, para programas pequenos a diferença pequena, mas para programas maiores como uma aplicação web essa diferença irá ficar bem maior.

Finalização

Neste artigo você aprendeu como utilizar a GraalVM para gerar binários de projetos JVM especialmente Kotlin, e executar esse binário final.

← voltar para o início