Algum tempo atrás, escrevi alguns posts sobre Coleta de Lixo em Java e Java é Passado por Valor. Depois disso, recebi muitos e-mails pedindo para explicar sobre Espaço de Heap em Java, Memória de Pilha em Java, Alocação de Memória em Java e quais são as diferenças entre eles. Você verá muitas referências à memória de heap e pilha em livros e tutoriais de Java EE, mas dificilmente uma explicação completa do que é memória de heap e pilha em termos de um programa.
Espaço de Heap em Java
O espaço de heap em Java é usado pelo tempo de execução do Java para alocar memória para objetos e classes da JRE. Sempre que criamos um objeto, ele é sempre criado no espaço de heap. A Coleta de Lixo é executada na memória de heap para liberar a memória usada por objetos que não têm nenhuma referência. Qualquer objeto criado no espaço de heap tem acesso global e pode ser referenciado de qualquer lugar da aplicação.
Memória de Pilha em Java
A memória da pilha do Java é usada para a execução de uma thread. Ela contém valores específicos do método que têm curta duração e referências a outros objetos no heap que estão sendo referenciados pelo método. A memória da pilha é sempre referenciada na ordem LIFO (Last-In-First-Out). Sempre que um método é invocado, um novo bloco é criado na memória da pilha para o método armazenar valores primitivos locais e referências a outros objetos no método. Assim que o método termina, o bloco se torna não utilizado e fica disponível para o próximo método. O tamanho da memória da pilha é muito menor em comparação com a memória do heap.
Heap e Memória da Pilha em Programas Java
Vamos entender o uso da memória do heap e da pilha com um programa simples.
package com.journaldev.test;
public class Memory {
public static void main(String[] args) { // Line 1
int i=1; // Line 2
Object obj = new Object(); // Line 3
Memory mem = new Memory(); // Line 4
mem.foo(obj); // Line 5
} // Line 9
private void foo(Object param) { // Line 6
String str = param.toString(); //// Line 7
System.out.println(str);
} // Line 8
}
A imagem abaixo mostra a memória da pilha e do heap em relação ao programa acima e como eles estão sendo usados para armazenar variáveis primitivas, objetos e referências. Vamos seguir os passos da execução do programa.
- Ao executarmos o programa, ele carrega todas as classes de tempo de execução na área do heap. Quando o método main() é encontrado na linha 1, o tempo de execução do Java cria memória da pilha a ser usada pela thread do método main().
- Estamos criando uma variável local primitiva na linha 2, então ela é criada e armazenada na memória de pilha do método main().
- Já que estamos criando um objeto na 3ª linha, ele é criado na memória heap e a memória de pilha contém a referência para ele. Um processo semelhante ocorre quando criamos o objeto Memory na 4ª linha.
- Agora, quando chamamos o método foo() na 5ª linha, um bloco no topo da pilha é criado para ser usado pelo método foo(). Como o Java é passado por valor, uma nova referência ao objeto é criada no bloco de pilha do foo() na 6ª linha.
- A string is created in the 7th line, it goes in the String Pool in the heap space and a reference is created in the foo() stack space for it.
- O método foo() é terminado na 8ª linha e, nesse momento, o bloco de memória alocado para foo() na pilha se torna livre.
- Na linha 9, o método main() termina e a memória de pilha criada para o método main() é destruída. Além disso, o programa termina nesta linha, portanto o Java Runtime libera toda a memória e encerra a execução do programa.
Diferença entre o Espaço de Heap e a Memória de Pilha em Java
Com base nas explicações acima, podemos facilmente concluir as seguintes diferenças entre a memória de heap e a memória de pilha.
- A memória heap é usada por todas as partes da aplicação, enquanto a memória de pilha é usada apenas por uma linha de execução.
- Sempre que um objeto é criado, ele é sempre armazenado no espaço Heap e a memória stack contém a referência a ele. A memória stack contém apenas variáveis primitivas locais e variáveis de referência a objetos no espaço heap.
- Os objetos armazenados no heap são globalmente acessíveis, enquanto a memória stack não pode ser acessada por outras threads.
- O gerenciamento de memória na stack é feito de forma LIFO, enquanto é mais complexo na memória Heap porque é usada globalmente. A memória Heap é dividida em Geração Jovem, Geração Antiga, etc., mais detalhes em Coleta de Lixo em Java.
- A memória stack é de curta duração, enquanto a memória heap vive desde o início até o final da execução do aplicativo.
- Podemos usar a opção -Xms e -Xmx da JVM para definir o tamanho inicial e o tamanho máximo da memória heap. Podemos usar -Xss para definir o tamanho da memória stack.
- Quando a memória stack está cheia, o tempo de execução do Java lança
java.lang.StackOverFlowError
, enquanto se a memória heap estiver cheia, ele lança o errojava.lang.OutOfMemoryError: Java Heap Space
. - O tamanho da memória stack é muito menor quando comparado com a memória heap. Devido à simplicidade na alocação de memória (LIFO), a memória stack é muito rápida quando comparada com a memória heap.
Isso é tudo sobre Espaço de Heap Java vs Memória Stack em termos de aplicativos Java, espero que isso esclareça suas dúvidas sobre alocação de memória quando qualquer programa Java é executado.
Referência: https://en.wikipedia.org/wiki/Java_memory_model.
Source:
https://www.digitalocean.com/community/tutorials/java-heap-space-vs-stack-memory