Pular para o conteúdo

Desmistificando o JVM, JRE e JDK

Se você está começando a estudar Java, provavelmente já encontrou três siglas que aparecem o tempo todo:

JVM, JRE e JDK.

À primeira vista, elas parecem representar praticamente a mesma coisa. E, para piorar, muitos materiais explicam esses conceitos usando definições bastante técnicas antes mesmo de explicar como eles se relacionam.

Uma forma simples de entender isso é imaginar que estamos falando de uma cozinha.

Vamos começar pelo conceito mais importante.

Quando escrevemos um programa Java, o código que criamos não é executado diretamente pelo sistema operacional.

Por exemplo, podemos escrever:

public class Main {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}

Esse código é transformado pelo compilador em bytecode, normalmente armazenado em um arquivo .class.

É aí que entram JVM, JRE e JDK.


A JVM (Java Virtual Machine) pode ser comparada ao cozinheiro da nossa cozinha.

É ela quem pega o bytecode Java e efetivamente executa o programa.

Quando você executa:

Janela do terminal
java Main

a JVM entra em ação.

Ela interpreta ou compila o bytecode para instruções que o computador consegue executar, utilizando técnicas como JIT (Just-In-Time compilation) durante a execução.

E aqui está uma das grandes ideias por trás do Java:

O mesmo bytecode pode ser executado em diferentes sistemas operacionais, desde que exista uma JVM adequada para aquele sistema.

Por isso, podemos ter:

Main.class
│
┌────────┼────────┐
↓ ↓ ↓
JVM JVM JVM
Windows Linux macOS
│ │ │
↓ ↓ ↓
CPU CPU CPU

O bytecode continua sendo o mesmo.

O que muda é a implementação da JVM responsável por conversar com o sistema operacional e o hardware.

É daí que vem a famosa ideia:

“Write once, run anywhere.”

Escreva uma vez, execute em qualquer lugar.


Agora imagine que o cozinheiro sozinho não consegue fazer muita coisa.

Ele precisa de uma cozinha, utensílios, ingredientes e toda a estrutura necessária para preparar o prato.

Essa é uma boa forma de imaginar o JRE (Java Runtime Environment).

Conceitualmente, o JRE representa o ambiente necessário para executar aplicações Java.

Podemos simplificar assim:

JRE
├── JVM
└── Bibliotecas necessárias para execução

Ou, usando nossa analogia:

JRE = Cozinha + Cozinheiro + Recursos necessários

Se você simplesmente quer executar uma aplicação Java, você não precisa necessariamente de todas as ferramentas utilizadas pelo desenvolvedor para construir aquela aplicação.

É a diferença entre:

“Quero preparar esta receita.”

e:

“Quero criar novas receitas.”

No primeiro caso, precisamos da estrutura necessária para cozinhar.

No segundo, precisamos de ferramentas adicionais.


É aí que entra o JDK (Java Development Kit).

Se o JRE representa o ambiente necessário para executar aplicações Java, o JDK representa o conjunto de ferramentas necessário para desenvolver essas aplicações.

Podemos imaginar:

JDK
├── JRE
│ └── JVM
└── Ferramentas de desenvolvimento

Entre essas ferramentas está o famoso:

Janela do terminal
javac

O javac é o compilador Java.

Quando fazemos:

Janela do terminal
javac Main.java

o compilador transforma nosso código-fonte:

Main.java

em bytecode:

Main.class

Depois, podemos executar esse bytecode utilizando a JVM:

Janela do terminal
java Main

Portanto, o fluxo simplificado seria:

Desenvolvedor
│
↓
Main.java
│
│ javac
↓
Main.class
│
│ JVM
↓
Programa rodando

Podemos resumir tudo em uma frase:

JDK desenvolve, JRE fornece o ambiente de execução e JVM executa o bytecode.

Ou, usando nossa analogia:

Conceito Analogia Responsabilidade
JVM 👨‍🍳 Cozinheiro Executa o bytecode
JRE 🍳 Cozinha Fornece o ambiente necessário para executar Java
JDK 🧰 Cozinha completa Fornece ferramentas para desenvolver aplicações Java

A relação pode ser visualizada desta maneira:

┌─────────────────────────────────┐
│ JDK │
│ │
│ ┌─────────────────────────┐ │
│ │ JRE │ │
│ │ │ │
│ │ ┌───────────┐ │ │
│ │ │ JVM │ │ │
│ │ └───────────┘ │ │
│ │ │ │
│ └─────────────────────────┘ │
│ │
│ + ferramentas de desenvolvimento│
└─────────────────────────────────┘

Essa representação é muito útil para entender os conceitos, mas existe uma ressalva importante.

Atualmente, especialmente a partir do Java 11, a ideia de instalar um “JRE separado” não funciona mais da mesma forma que funcionava em versões antigas do Java.

Distribuições modernas do OpenJDK normalmente são distribuídas como JDKs, e ferramentas como jlink podem ser utilizadas para criar runtimes personalizados.

Por isso, hoje é comum um desenvolvedor simplesmente instalar um JDK, como:

OpenJDK
Temurin
Oracle JDK
Amazon Corretto

e utilizar esse ambiente tanto para desenvolver quanto para executar suas aplicações.

Isso não torna o conceito de JRE inútil.

Pelo contrário.

A distinção continua sendo bastante útil para entender o que uma aplicação Java precisa para ser executada e quais componentes fazem parte do ecossistema Java.


Aqui existe outra confusão bastante comum.

Quando falamos “Java”, podemos estar falando de coisas diferentes:

Java
├── Linguagem Java
├── Plataforma Java
├── JVM
├── Bibliotecas
└── Ferramentas do JDK

A linguagem é aquilo que escrevemos:

System.out.println("Hello World");

O compilador transforma esse código em bytecode.

A JVM executa esse bytecode.

E o JDK fornece as ferramentas necessárias para construir todo esse processo.


Voltando para nossa cozinha, podemos pensar em todo o processo assim:

Você é o desenvolvedor.

Você escreve uma receita:

Main.java

O JDK fornece as ferramentas necessárias para transformar essa receita em algo que possa ser executado.

O JRE representa a estrutura necessária para executar aquilo.

E a JVM é quem efetivamente prepara a receita.

No final:

Você
│
│ escreve
↓
Java (.java)
│
│ JDK / javac
↓
Bytecode (.class)
│
│ JVM
↓
Aplicação executando

Essa separação é uma das características que tornam o ecossistema Java tão interessante.

O programa não precisa ser compilado diretamente para cada sistema operacional.

Ele é compilado para bytecode, e a JVM de cada plataforma fica responsável por executar esse bytecode.


Se você está começando no Java, não precisa decorar dezenas de definições.

Lembre apenas:

JDK → ferramentas para desenvolver

JRE → ambiente para executar

JVM → máquina virtual que executa o bytecode

Ou, na nossa cozinha:

👨‍💻 JDK é o kit do desenvolvedor.

🍳 JRE é o ambiente de execução.

👨‍🍳 JVM é quem executa o programa.

Entendendo essa relação, fica muito mais fácil compreender o restante do ecossistema Java.