Aula 62 | Uso de Memória em Java
A memória RAM (Random Access Memory, ou Memória de Acesso Aleatório) é um componente físico do computador que armazena temporariamente os dados e instruções que estão sendo usados naquele momento. Diferente do disco rígido (HD ou SSD), que guarda informações de forma permanente, a RAM é rápida e volátil — ou seja, tudo que está nela é apagado quando o programa termina ou o computador é desligado.
Quando um programa Java é executado, o computador reserva espaços na sua memória RAM para guardar cada variável, objeto e constante. Cada espaço reservado recebe um endereço de memória — um número que identifica exatamente onde aquela informação está armazenada.
new, a variável-referência guarda o endereço
desse objeto, não o objeto em si.
Para entender o conceito de endereço de memória, pense em uma rua com várias casas. Cada casa tem um número que a identifica de forma única: 125, 129, 133, 137, 141… Quando você quer encontrar alguém, não precisa carregar a casa inteira — basta saber o número dela. Com esse número, você chega até a casa e encontra o que há lá dentro: os móveis, as pessoas, os objetos.
Cada casa da rua tem um número único, assim como cada compartimento da memória tem um endereço único.
Na memória do computador é exatamente igual: cada compartimento de memória tem um endereço único (como o número da casa). O programa usa esse endereço para localizar onde uma informação está guardada. Essa analogia será útil ao longo de toda a aula — guarde-a bem:
🏠 Número da casa = endereço do compartimento de memória.
📦 O que há dentro da casa = o conteúdo (dado/valor) guardado naquele endereço.
O Java divide a memória em regiões. As três principais que aparecem no exemplo desta aula são:
Armazena variáveis locais e referências a objetos. Na nossa analogia, o Stack guarda apenas o número da casa (o endereço) — não o conteúdo dela.
Armazena os objetos criados com new. Na analogia, o Heap é a
casa em si com tudo dentro — o endereço e todo o conteúdo
(os atributos do objeto). O Stack guarda apenas o número que aponta para essa casa.
Armazena variáveis e constantes declaradas como static. Existem
durante toda a execução do programa, independentemente de objetos.
Vamos usar o mesmo programa da Parte 1 para entender onde cada variável e objeto ficam guardados na memória.
public class PesoAltura {
int peso; // peso em quilogramas
int altura; // altura em centímetros
}
public class EstruturaSimples {
public static final int alturaMaxima = 225; // constante estática
public static void main(String[] args) {
PesoAltura pessoa1 = new PesoAltura(); // cria objeto no Heap
pessoa1.peso = 80;
pessoa1.altura = 185;
System.out.print("Peso: " + pessoa1.peso + ", Altura " + pessoa1.altura + ". ");
if (pessoa1.altura > alturaMaxima)
System.out.println("Altura acima da máxima.");
else
System.out.println("Altura abaixo da máxima.");
}
}
Saída no terminal:
Peso: 80, Altura 185. Altura abaixo da máxima.
O diagrama abaixo ilustra o que acontece na memória quando o programa é executado. Os números em vermelho (ex.: 9742, 3408) representam endereços de memória fictícios usados para mostrar como as referências funcionam.
pessoa1 está no Stack e guarda
o endereço 3408. Esse endereço aponta para o local no Heap onde o objeto
PesoAltura de fato existe, com seus atributos peso = 80 e
altura = 185. A constante alturaMaxima fica na área estática,
com endereço 9742.
peso, a altura e os demais atributos
do objeto. Para saber o que há na casa, o Java primeiro lê o número na agenda (Stack) e depois
vai até a casa (Heap).
Clique em cada passo para ver o que acontece na memória durante a execução:
A constante alturaMaxima é carregada na área estática
da memória com o valor 225. Como é static, ela existe
desde o início da execução, antes mesmo de qualquer objeto ser criado.
Seu endereço fictício é 9742.
O método main é chamado. O parâmetro args é criado
no Stack. Como é um objeto array, ele guarda um endereço de memória
(fictício 9742) que aponta para o array real no Heap.
O new PesoAltura() cria um objeto no Heap
no endereço 3408. A variável pessoa1 é criada
no Stack e recebe esse endereço (3408)
como valor. Por isso dizemos que pessoa1 é uma
referência ao objeto.
Usando o operador ponto (.), o Java segue o endereço
guardado em pessoa1 (que é 3408) até o objeto
no Heap e atribui os valores 80 e 185 aos
atributos peso e altura daquele objeto.
O Java busca pessoa1.altura no Heap (endereço 3408)
e encontra 185. Em seguida busca alturaMaxima
na área estática (endereço 9742) e encontra 225.
Como 185 < 225, a condição é false e o bloco
else é executado, imprimindo a mensagem.
Peso: 80, Altura 185. Altura abaixo da máxima.
Existe uma diferença fundamental entre guardar um valor primitivo e guardar uma referência a um objeto:
| Tipo | Exemplos | O que é guardado no Stack | Onde fica o dado real |
|---|---|---|---|
| Primitivo | int, double, boolean, char |
O valor diretamente (ex.: 80) |
No próprio Stack |
| Referência | String, qualquer classe (PesoAltura, etc.) |
Um endereço que aponta para o objeto (ex.: 3408) |
No Heap |
int x = 10;, o valor 10 fica diretamente
na variável x. Mas quando faz
PesoAltura pessoa1 = new PesoAltura();, a variável pessoa1
guarda apenas o endereço do objeto, não o objeto em si!
Veja a diferença concreta entre os dois tipos. Considere o código:
int idade = 30; // variável PRIMITIVA PesoAltura pessoa1 = new PesoAltura(); // variável de REFERÊNCIA pessoa1.peso = 80; pessoa1.altura = 185;
int idade = 30;O valor fica diretamente no Stack. Não há Heap envolvido — é como ter o dado escrito na própria agenda, sem precisar ir a casa nenhuma.
30 está anotado direto na agenda
(Stack). Não existe "casa" separada — o conteúdo é o próprio número guardado ali.
PesoAltura pessoa1 = new PesoAltura();
A variável guarda no Stack apenas o endereço (ex.: 3408). O
objeto real, com seus atributos, fica no Heap. O Stack aponta para o Heap.
3408). A casa de número 3408 (Heap) é que contém de fato o
peso = 80 e a altura = 185. Para ler um atributo, o Java segue
o número até a casa.
Resumindo a diferença:
🔴 Primitivo (idade): o Stack guarda o próprio valor
(30). Não há endereço apontando para lugar nenhum.
🟢 Referência (pessoa1): o Stack guarda um endereço
(3408) e o conteúdo real (peso, altura) fica no Heap,
naquele endereço.
✅ A memória RAM é dividida em regiões: Stack, Heap e Área Estática.
✅ Cada variável e objeto ocupa um endereço de memória único.
✅ Variáveis de tipos primitivos (int, double…) guardam o valor diretamente no Stack.
✅ Variáveis de referência (objetos) guardam no Stack o endereço que aponta para o objeto no Heap.
✅ Constantes static final ficam na área estática e existem durante toda a execução.
✅ O operador ponto (.) faz o Java seguir o endereço guardado na referência até o objeto real no Heap.
Crie uma classe chamada Carro com os atributos String modelo,
int ano e double preco. Na classe principal, declare uma
constante static final int anoMinimo = 2000. Crie dois objetos da classe
Carro, preencha seus atributos e use um if-else para verificar
se o ano de cada carro é maior ou igual a anoMinimo, imprimindo uma mensagem
adequada para cada caso.
public class Carro {
String modelo;
int ano;
double preco;
}
public class DesafioCarro {
public static final int anoMinimo = 2000;
public static void main(String[] args) {
Carro c1 = new Carro();
c1.modelo = "Gol";
c1.ano = 1998;
c1.preco = 15000.0;
Carro c2 = new Carro();
c2.modelo = "HB20";
c2.ano = 2021;
c2.preco = 72000.0;
System.out.print("Carro: " + c1.modelo + " | Ano: " + c1.ano + " -> ");
if (c1.ano >= anoMinimo)
System.out.println("Ano aceito.");
else
System.out.println("Ano abaixo do mínimo.");
System.out.print("Carro: " + c2.modelo + " | Ano: " + c2.ano + " -> ");
if (c2.ano >= anoMinimo)
System.out.println("Ano aceito.");
else
System.out.println("Ano abaixo do mínimo.");
}
}
Saída esperada:
Carro: Gol | Ano: 1998 -> Ano abaixo do mínimo.
Carro: HB20 | Ano: 2021 -> Ano aceito.
Reforce o conteúdo desta aula com mais dois exercícios práticos: