O gerenciamento de memória no desenvolvimento Java e o funcionamento do Garbage Collector
- #Java
Lembro de quando era criança e para fugir do tédio, em meados de 2014, alguns dispositivos móveis tinham joguinhos instalados, quando abertos a primeira coisa que se dava de cara é aquela logo de uma xícara e o nome “Java”.No momento em que decidimos adentrar no mundo da programação, ter noções de algoritmos e a existência das linguagens de programação, vem á tona a lembrança daquela logo que vimos bem anos atrás e o desenvolvimento do pensamento curioso e analítico quando começamos desenvolver os primeiros algoritmos em alguma linguagem de programação, queremos saber o que acontece na execução desses algoritmos, através de uma IDE , em especial na memória do nosso desktop.
Como programadores iniciantes, o estudo se torna desafiador ao compreender “para onde vai os dados na memória?”,” de onde vêm este erro?” , “será que o meu algoritmo apresenta performance ao usuário final ou cliente?”. Uma boa compreensão dos conceitos de memória em programação, o que é garbage collector , em especial utilizando Java como linguagem e a utilização dos pilares da programação orientada a objetos contribui para o aprendizado efetivo e o amplia para um conhecimento multilinguagens.
No desenvolvimento de um algoritmo, fazemos a declaração das famosas variáveis que tem como conceito: ¹ uma representação simbólica na memória do computador que armazena um tipo de dado que pode variar ao decorrer da execução de um sistema. Esses algoritmos são executados na Random Acess Mémory, a memória RAM, traduzindo em português como “memória de acesso aleatório”, ²que é uma memória de curto prazo do computador, onde são armazenados os dados que o processador está utilizando naquele momento ao decorrer da execução de um algoritmo ou programa.
Declarando as variáveis em Java, do tipo valor, podemos ver a aplicação dos conceitos de alocação estática e dinâmica de memória, no momento de sua criação.
Ao declararmos o tipo de dado da variável e como ela será identificada, sendo criada após sua atribuição, que pode ser um valor atribuído diretamente ou definido pelos mecanismos de entrada pelo usuário.
Ao entrar em execução, os dados dessa variável são armazenados “em caixa”, na memória STACK, que significa “pilha”, que é um endereço da memória RAM, fazendo alusão a um “empilhamento de caixas”, vemos a aplicação do conceito de alocação estática de memória.
³A memória STACK, cria um ENDEREÇO DE MEMÓRIA que identifica essa “caixa” onde o dado está armazenado, sendo identificado como HASH.
Exemplificando, se declaramos e criamos a variável da seguinte maneira:
public class StackExample {
public static void main(String[] args) {
// Variável do tipo primitivo (tipo valor)
int number = 42;
// Exibe o valor da variável
System.out.println("Valor armazenado: " + number)
}
}
O que acontece pode ser visivelmente representado desta forma:
Fonte: ChatGpt; prompt: “reproduza em ilustração como uma variável do tipo valor é alocada na memória estática stack com endereço de memória”, endereço" hash" localizado abaixo da caixa.
Em linguagens de programação que sejam orientada a objetos, a aplicação desses conceitos pode mudar um pouco a forma como o código é desenvolvido. A aplicação de POO, em Java, reproduzem ações como: a criação de classes, a criação e a definição do nível de acesso de seus atributos e a instanciação de um objeto. Em um algoritmo desenvolvido em Java, aplicando as práticas de POO, vemos a aplicação do conceito de alocação dinâmica de memória.
As variáveis declaradas e criadas em um código orientado a objetos, em sua maioria do tipo classe, recebem a definição de variáveis do tipo referência.
⁴Elas são armazenadas em uma área da memória de nome HEAP, que significa a “junção de pilhas, caixas compostas”, pois apontam, ou seja, fazem referência para as caixas que possuem dados, onde esses dados serão objetos, na memória stack.
Exemplificando utilizando um código em Java orientado a objetos:
class Person {
String name;
int age;
// Construtor
Person(String name, int age) {
this.name = name;
this.age = age;
}
// Método para exibir informações
void showInfo() {
System.out.println("Nome: " + name + ", Idade: " + age);
}
Código de funcionamento do sistema com método "main":
public class ReferenceExample {
public static void main(String[] args) {
// Variável de referência (armazenada na Stack)
Person personRef;
// Criação do objeto (armazenado na Heap)
personRef = new Person("João", 25);
// A variável personRef guarda o endereço do objeto na Heap
System.out.println("Referência (endereço na Heap): " + personRef);
// Usando a referência para acessar dados do objeto
personRef.showInfo();
}
}