<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Nathalia Nóbrega - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Aprenda a codificar - de graça. Tutoriais de programação em Python, JavaScript, Linux e muito mais. ]]>
        </description>
        <link>https://www.freecodecamp.org/portuguese/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Nathalia Nóbrega - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/portuguese/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 24 May 2026 19:37:30 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/portuguese/news/author/nathalia/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Tipos de dados estruturados em C explicados ]]>
                </title>
                <description>
                    <![CDATA[ ‌  Existem variáveis de diferentes tipos na linguagem C, como os ints, chars e  floats. Todos permitem o armazenamento de dados. Também temos os arrays, que permitem o agrupamento de itens de dados que possuem o mesmo tipo. Porém, na realidade, nem sempre vamos ter o luxo de ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/tipos-de-dados-estruturados-em-c-explicados/</link>
                <guid isPermaLink="false">655413e4f2994303ed34352d</guid>
                
                    <category>
                        <![CDATA[ Linguagem C ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Nathalia Nóbrega ]]>
                </dc:creator>
                <pubDate>Sun, 19 May 2024 23:14:30 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2024/01/c.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/structured-data-types-in-c-explained/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Structured Data Types in C Explained</a>
      </p><p>‌ &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </p><p>Existem variáveis de diferentes tipos na linguagem C, como os <code>int</code>s, <code>char</code>s e <code>float</code>s. Todos permitem o armazenamento de dados.</p><p>Também temos os <em>arrays</em>, que permitem o agrupamento de itens de dados que possuem o mesmo tipo.</p><p>Porém, na realidade, nem sempre vamos ter o luxo de possuir dados de apenas um tipo. É nesse cenário que utilizamos as <strong>estruturas. </strong>Neste artigo, vamos aprender mais sobre tipos de dados estruturados em C.</p><h2 id="-ndice">Índice</h2><p><strong>A. <a href="https://www.freecodecamp.org/portuguese/news/tipos-de-dados-estruturados-em-c-explicados/#fundamentos">Fundamentos</a></strong></p><ol><li><a href="https://www.freecodecamp.org/portuguese/news/tipos-de-dados-estruturados-em-c-explicados/#\31%20-defini-o-e-declara-o">Definição e declaração</a></li><li><a href="https://www.freecodecamp.org/portuguese/news/tipos-de-dados-estruturados-em-c-explicados/#\32%20-inicializa-o-e-acesso-aos-membros-de-uma-estrutura">Inicialização e acesso aos membros de uma estrutura</a></li><li><a href="https://www.freecodecamp.org/portuguese/news/tipos-de-dados-estruturados-em-c-explicados/#\33%20-opera-es-com-a-vari-vel-de-estrutura">Operações com uma variável de estrutura</a></li><li><a href="https://www.freecodecamp.org/portuguese/news/tipos-de-dados-estruturados-em-c-explicados/#\34%20-array-de-uma-estrutura">Array de uma estrutura</a></li><li><a href="https://www.freecodecamp.org/portuguese/news/tipos-de-dados-estruturados-em-c-explicados/#\35%20-estruturas-aninhadas">Estruturas aninhadas</a></li></ol><p><strong>B. <a href="https://www.freecodecamp.org/portuguese/news/tipos-de-dados-estruturados-em-c-explicados/#aloca-o-de-mem-ria">Alocação de memória</a></strong></p><ol><li><a href="https://www.freecodecamp.org/portuguese/news/tipos-de-dados-estruturados-em-c-explicados/#\31%20-alinhamento-de-dados">Alinhamento de dados</a></li><li><a href="https://www.freecodecamp.org/portuguese/news/tipos-de-dados-estruturados-em-c-explicados/#\32%20-preenchimento-de-estruturas">Preenchimento de estruturas</a></li><li><a href="https://www.freecodecamp.org/portuguese/news/tipos-de-dados-estruturados-em-c-explicados/#\33%20-alinhamento-de-membro-de-estrutura">Alinhamento de membro de estrutura</a></li><li><a href="https://www.freecodecamp.org/portuguese/news/tipos-de-dados-estruturados-em-c-explicados/#\34%20-empacotamento-de-estrutura">Empacotamento de estrutura</a></li></ol><p><strong>C. <a href="https://www.freecodecamp.org/portuguese/news/tipos-de-dados-estruturados-em-c-explicados/#ponteiros">Ponteiros</a></strong></p><ol><li><a href="https://www.freecodecamp.org/portuguese/news/tipos-de-dados-estruturados-em-c-explicados/#\31%20-ponteiro-como-um-membro">Ponteiro como um membro</a></li><li><a href="https://www.freecodecamp.org/portuguese/news/tipos-de-dados-estruturados-em-c-explicados/#\32%20-ponteiro-para-estrutura">Ponteiro para estrutura</a></li><li><a href="https://www.freecodecamp.org/portuguese/news/tipos-de-dados-estruturados-em-c-explicados/#\33%20-ponteiro-e-array-de-estrutura">Ponteiro e array de estrutura</a></li></ol><p><strong>D. <a href="https://www.freecodecamp.org/portuguese/news/tipos-de-dados-estruturados-em-c-explicados/#fun-es">Funções</a></strong></p><ol><li><a href="https://www.freecodecamp.org/portuguese/news/tipos-de-dados-estruturados-em-c-explicados/#\31%20-fun-o-como-membro">Função como membro</a></li><li><a href="https://www.freecodecamp.org/portuguese/news/tipos-de-dados-estruturados-em-c-explicados/#\32%20-estrutura-como-argumento-de-fun-o">Estrutura como argumento de função</a></li><li><a href="https://www.freecodecamp.org/portuguese/news/tipos-de-dados-estruturados-em-c-explicados/#\33%20-estrutura-como-retorno-de-fun-o">Estrutura como retorno de uma função</a></li></ol><p><strong>E. <a href="https://www.freecodecamp.org/portuguese/news/tipos-de-dados-estruturados-em-c-explicados/#estrutura-autorreferencial">Estrutura autorreferencial</a></strong></p><p><strong>F. <a href="https://www.freecodecamp.org/portuguese/news/tipos-de-dados-estruturados-em-c-explicados/#conclus-o">Conclusão</a></strong></p><p>Vamos começar!</p><h2 id="fundamentos">Fundamentos</h2><h3 id="1-defini-o-e-declara-o">1. Definição e declaração</h3><p>Uma estrutura é uma <strong>coleção </strong>de uma ou mais variáveis, possivelmente de tipos distintos, agrupadas em um nome comum. É um tipo de dado <strong>definido pelo usuário</strong>.</p><p>As estruturas auxiliam na organização de dados complicados em programas grandes, já que permitem com que um grupo de variáveis logicamente associadas entre si sejam tratadas desse modo.</p><p>Por exemplo, um estudante pode ter as propriedades nome, idade, sexo e notas. Podemos criar um array do tipo <code>char</code> para a variável <code>nome</code>, um <code>int</code> para <code>matrícula</code>, um <code>char</code> para <code>sexo</code> e um array do tipo <code>int</code> para as <code>notas</code>.</p><p>Porém, se existem 20 ou 100 estudantes, vai ser difícil lidar com essas variáveis.</p><p>Podemos declarar uma estrutura utilizando a palavra reservada <code>struct</code> de acordo com a sintaxe abaixo:</p><pre><code class="language-c"> /* Sintaxe */
 struct nomeEstrutura
        {
            tipoDado variavelMembro1;
            tipoDado variavelMembro2;
            ...
        };

 /* Exemplo */
struct estudante
    {
        char nome[20];
        int matricula;
        char sexo;
        int notas[5];
    };
</code></pre><p>O código acima define um novo tipo de dado, <code>struct estudante</code>. Cada variável pertencente a esse tipo de dado vai possuir um <code>nome[20]</code>, <code>matricula</code>, <code>sexo</code> e <code>notas[5]</code>. Essas propriedades citadas são os <strong>membros</strong> da estrutura.</p><p>Uma vez que a estrutura é declarada como um novo tipo de dado, podemos criar as variáveis que possuem o tipo dessa estrutura.</p><pre><code class="language-c"> /* Declaração de variável */
struct nomeEstrutura variavelEstrutura;

 /* Exemplo /*
struct estudante est1;
struct estudante est2,est3,est4;</code></pre><p>Cada variável de <code>struct estudante</code> tem sua própria cópia das propriedades membro.</p><p><strong>Algumas informações importantes:</strong></p><ol><li>Os membros da estrutura não ocupam memória alguma até que uma variável de estrutura seja criada.</li><li>Você já deve ter notado que estamos usando a palavra <code>struct</code> para declarar a variável também. Não é um pouco tedioso? </li></ol><p>Se utilizarmos a palavra reservada <code>typedef</code> na declaração da estrutura, podemos evitar a repetição da palavra <code>struct</code>. </p><pre><code class="language-c">typedef struct estudantes
    {
        char nome[20];
        int matricula;
        char sexo;
        int notas[5];
    } ESTUDANTE; 

/* ou */
typedef struct
    {
        char nome[20];
        int matricula;
        char sexo;
        int notas[5];
    } ESTUDANTE; 


ESTUDANTE est1,est2,est3,est4;
</code></pre><p>Como convenção, são utilizadas letras <strong>maiúsculas</strong> para definição de tipos (como <code>ESTUDANTE</code>).</p><p>3. A definição de estrutura e declaração de variável podem ser combinadas desta maneira: </p><pre><code class="language-c">struct estudante
    {
        char nome[20];
        int matricula;
        chat sexo;
        int notas[5];
    }est1, est2, est3, est4;
</code></pre><p>4. O uso de <code>nomeEstrutura</code> para declarar a estrutura é opcional. O código abaixo, por exemplo, é totalmente válido.</p><pre><code class="language-c">struct
    {
        char nome[20];
        int matricula;
        char sexo;
        int notas[5];
    }est1, est2, est3, est4;
</code></pre><p>5. &nbsp;Estruturas geralmente são declaradas no começo do arquivo do código-fonte, antes mesmo das definições das funções (você já vai ver o motivo).</p><p>6. &nbsp;A linguagem C não permite a inicialização de uma variável dentro da declaração de uma estrutura.</p><h3 id="2-inicializa-o-e-acesso-aos-membros-de-uma-estrutura">2. Inicialização e acesso aos membros de uma estrutura</h3><p>Como qualquer outra variável, uma variável de estrutura também pode ser inicializada na mesma linha onde foi declarada.</p><pre><code class="language-c"> /* Inicialização de variável */
nomeEstrutura nomeVariavel = { valor1, valor2,...};

 /* Exemplo */
typedef struct
    {
        char nome[20];
        int matricula;
        char sexo;
        int notas[5];
    }ESTUDANTE;

void main(){
ESTUDANTE est1 = { "Alex", 43, 'M', {76, 78, 56, 98, 92}};
ESTUDANTE est2 = { "Max", 33, 'M', {87, 84, 82, 96, 78}};
}
</code></pre><p>Para acessar os membros, precisamos usar o <code>.</code> (<strong>operador de ponto</strong>)</p><pre><code class="language-c"> /* Acessando os membros de uma estrutura */
variavelEstrutura.membroVariavel;

/* Exemplo */
 printf("Nome: %s\n", est1.nome);
 printf("Matricula: %d\n", est1.matricula);
 printf("Sexo: %c\n", est1.sexo);
 for( int i = 0; i &lt; 5; i++)
   printf("Notas na matéria n°%d: %d\n", i, est1.notas[i]);

/* Saída */
Nome: Alex
Matricula: 43
Sexo: M
Notas na matéria n°0: 73
Notas na matéria n°1: 78
Notas na matéria n°2: 56
Notas na matéria n°3: 89
Notas na matéria n°4: 92
</code></pre><p>Os membros podem ser inicializados na declaração da variável em qualquer ordem, apenas utilizando o <code>.</code>.</p><pre><code class="language-c">ESTUDANTE est3 = { .sexo = 'M', .matricula = 23, .nome = "Gasly", .notas = { 99, 45, 67, 78, 94}};
</code></pre><p>Também podemos inicializar os primeiros membros e deixar os membros restantes vazios. Contudo, os membros que não foram inicializados devem estar <strong>somente </strong>no final da lista.</p><p>Inteiros e números de ponto flutuante que não foram inicializados tem um valor padrão <code>0</code>. Enquanto que caracteres e <em>strings </em>não inicializados possuem o valor padrão <code>\0</code> (NULL) .</p><pre><code class="language-c">ESTUDANTE est4 = { "Mário", 65};
 /* Equivalente a { "Mario", 65, '\0', { 0, 0, 0, 0, 0} } */
</code></pre><h3 id="3-opera-es-com-a-vari-vel-de-estrutura">3. Operações com a variável de estrutura</h3><p>Ao contrário das variáveis de tipos primitivos, não podemos utilizar operadores aritméticos como <code>+</code>, <code>-</code>, <code>*</code>, <code>/</code> para variáveis de estrutura. Também não é possível o uso de operadores relacionais e de igualdade.</p><p>Contudo, podemos copiar uma variável de estrutura para outra, desde que pertençam à mesma estrutura.</p><pre><code class="language-c"> /* Operações inválidas */
est1 + est2
est1 - est2
est1 == est2
est1 != est2

 /* Operação válida */
est1 = est2
</code></pre><p>Para comparar as variáveis de estrutura, vamos comparar os membros de cada uma individualmente.</p><pre><code class="language-c">#include &lt;stdio.h&gt;
#include &lt;string.h&gt;

 struct estudante
    {
        char nome[20];
        double matricula;
        char sexo;
        int notas[5];
    }est1,est2;


void main()
{
    struct estudante est1= { "Alex", 43, 'M', {76, 78, 56, 98, 92}};
    struct estudante est2 = { "Max", 33, 'M', {87, 84, 82, 96, 78}};

    if( strcmp(est1.nome,est2.nome) == 0 &amp;&amp; est1.matricula == est2.matricula)
        printf("Os dois dados pertencem ao mesmo estudante.\n");
    else printf("Dados diferentes, estudantes diferentes.\n");

     /* Copiando a variável de estrutura */
    est2 = est1;

    if( strcmp(est1.name,est2.name) == 0 &amp;&amp; est1.matricula == est2.matricula)
        printf("Os dois dados pertencem ao mesmo estudante.\n");
    else printf("Dados diferentes, estudantes diferentes.\n");
}

 /* Saida */
Os dois dados pertencem ao mesmo estudante.

Dados diferentes, estudantes diferentes.

</code></pre><h3 id="4-array-de-uma-estrutura">4. Array de uma estrutura</h3><p>Você deve ter percebido que criamos 4 variáveis diferentes do tipo <code>struct student</code> para armazenar os dados de 4 estudantes.</p><p>Uma maneira melhor de armazenar esses dados seria criar um array de <code>struct student</code> (da mesma maneira que um array de <code>int</code>s )</p><pre><code class="language-c">struct estudante
    {
        char nome[20];
        double matricula;
        char sexo;
        int notas[5];
    };

struct estudante estu[4];
</code></pre><p>Para acessar os elementos do array <code>estu</code> e os membros de cada elemento, podemos utilizar laços de repetição (<em>loops</em>).</p><pre><code class="language-c"> /* Registrando valores para os estudantes */

for(int i = 0; i &lt; 4; i++)
    {
        printf("Digite o nome:\n");
        scanf("%s",&amp;estu[i].nome);
        printf("Digite a matrícula:\n");
        scanf("%d",&amp;estu[i].matricula);
        printf("Digite o sexo:\n");
        scanf(" %c",&amp;estu[i].sexo);

        for( int j = 0; j &lt; 5; j++)
        {
            printf("Digite as notas da matéria n°%d:\n",j);
            scanf("%d",&amp;estu[i].notas[j]);
        }

        printf("\n-------------------\n\n");
    }

 /* Calculando a média de notas e imprimindo o resultado */

for(int i = 0; i &lt; 4; i++)
    {
        float soma = 0;
        for( int j = 0; j &lt; 5; j++)
        {
            soma += estu[i].notas[j];
        }

        printf("Nome: %s\nMédia = %.2f\n\n", estu[i].nome,soma/5);
    }
</code></pre><h3 id="5-estruturas-aninhadas">5. Estruturas aninhadas</h3><p>Aninhar uma estrutura significa ter uma ou mais variáveis de estrutura dentro de uma outra estrutura. Do mesmo modo com que declaramos um membro do tipo <code>int</code> ou um membro do tipo <code>char</code>, podemos também declarar uma variável de estrutura como um membro.</p><pre><code class="language-c">struct nascimento
    {
       int dia;
       int mes;
       int ano;
    };

struct estudante
    {
        char nome[20];
        int matricula;
        char sexo;
        int notas[5];
        struct nascimento dataNascimento;
    };

void main(){
 struct estudante estu1;
</code></pre><p>A variável de estrutura <code>dataNascimento</code> de tipo <code>struct nascimento</code> está aninhada dentro de <code>struct estudante</code>. É importante frisar que você <strong>não</strong> consegue aninhar uma variável de estrutura do tipo <code>struct estudante</code> dentro de <code>struct estudante</code>.</p><p>Perceba que a estrutura que vai ser aninhada deve ser declarada antes. Usando o <code>.</code>, podemos acessar os membros contidos dentro da estrutura interna, assim como os outros membros.</p><pre><code class="language-c"> /* Exemplo */
estu1.dataNascimento.dia
estu1.dataNascimento.mes
estu1.dataNascimento.ano
estu1.nome
</code></pre><p>Variáveis de estrutura de diferentes tipos podem ser aninhadas.</p><pre><code class="language-c">struct nascimento
    {
       int dia;
       int mes;
       int ano;
    };
 
struct parentesco
    {
        char nomePai[20];
        char nomeMae[20];
    };

struct estudante
    {
        char nome[20];
        int matricula;
        char sexo;
        int notas[5];
        struct nascimento dataNascimento;
        struct parentesco pais;
    };
</code></pre><h2 id="aloca-o-de-mem-ria">Alocação de memória</h2><p>Quando uma variável de estrutura de um certo tipo é declarada, os membros da estrutura são alocados em memória de maneira contígua (adjacente). </p><pre><code class="language-c">struct estudante
    {
        char nome[20];
        int matricula;
        char sexo;
        int notas[5];
    } estu1;
</code></pre><p>Aqui, haverá memória sendo alocada para <code>nome[20</code>, seguido de <code>matricula</code>, <code>sexo</code>, e <code>notas[5]</code>. Isso implica que o tamanho de <code>estu1</code> ou de <code>struct estudante</code> será a soma do tamanho dos membros, certo? Vamos dar uma olhada.</p><pre><code class="language-c">void main()
{
    printf("Soma do tamanho dos membros = %I64d bytes\n", sizeof(estu1.nome) + sizeof(estu1.matricula) + sizeof(estu1.sexo) + sizeof(estu1.notas));
    printf("Usando o operador sizeof() = %I64d bytes\n",sizeof(estu1));
}

 /* Saída */
Soma do tamanho dos membros =  45 bytes
Usando o operador sizeof() = 48 bytes
</code></pre><blockquote>Já que o operador <code>sizeof()</code> retorna um <code>long long unsigned int</code>, utilize <code>%I64D</code> para especificar o formato. Você talvez precise usar <code>%llu</code> ou <code>lld</code>, dependendo do seu compilador.</blockquote><blockquote>Usar <code>%d</code> retornará um aviso - &nbsp;format '%d' expects argument of type 'int', but argument 2 has type 'long long unsigned int'. (<strong>formato '%d' pede um argumento do tipo 'int', mas o argumento 2 tem tipo 'long long unsigned int'</strong>).</blockquote><p>Utilizando o operador <code>sizeof()</code> na variável de estrutura, tivemos 3 bytes a mais do que a soma do tamanho dos membros. Por que? Onde estão esses 3 bytes na memória? </p><p>Vamos responder à segunda pergunta primeiro. Podemos imprimir os endereços de memória dos membros para achar estes 3 bytes.</p><pre><code class="language-c">void main()
{
    printf("Endereço do membro 'nome' = %d\n", &amp;estu1.nome);
    printf("Endereço do membro 'matricula' = %d\n", &amp;estu1.matricula);
    printf("Endereço do membro 'sexo' = %d\n", &amp;estu1.sexo);
    printf("Endereço do membro 'notas' = %d\n", &amp;estu1.notas);
}

 /* Saída */
Endereço do membro 'nome' = 4225408
Endereço do membro 'matricula' = 4225428
Endereço do membro 'sexo' = 4225432
Endereço do membro 'notas' = 4225436
</code></pre><p>Podemos ver que o array <code>notas[5]</code>, ao invés de estar sendo alocado no endereço <code>4225433</code>, está no endereço <code>4224536</code>. Por que isso ocorre?</p><h3 id="1-alinhamento-de-dados">1. Alinhamento de dados</h3><p>Antes de darmos uma olhada no alinhamento de dados, é importante entender como o processador lê dados da memória.</p><p>Um processador lê <strong>uma palavra</strong> em um ciclo. Essa palavra possui <strong>4 bytes</strong> para um processador de <strong>32 bits </strong>e <strong>8 bytes</strong> para um de <strong>64 bits</strong>. Quanto menor o número de ciclos, melhor o desempenho da CPU.</p><p>Um modo de alcançar um menor número de ciclos é por meio do <strong>alinhamento </strong>de dados. Na prática, alinhar é quando uma <em>variável de tamanho <code>t</code> de um tipo primitivo qualquer é armazenada em um endereço que é múltiplo de </em><code><em>t</em></code><em>. &nbsp;</em>Esse processo ocorre por padrão.</p><p><strong>Endereços alinhados para certos tipos de dados</strong></p><!--kg-card-begin: html--><table>
    <tbody><tr>
        <th> Tipos de dados </th>
        <th> Tamanho (em bytes)</th>
        <th> Endereço </th>
    </tr>
    <tr>
        <td>char</td>
        <td>1</td>
        <td>múltiplo de 1</td>
    </tr>
    <tr>
        <td>short</td>
        <td>2</td>
        <td>múltiplo de 2</td>
    </tr>
    <tr>
        <td>int, float</td>
        <td>4</td>
        <td>múltiplo de 4</td>
    </tr>
    <tr>
        <td>double, long, * (ponteiros)</td>
        <td>8</td>
        <td>múltiplo de 8</td>
    </tr>
    <tr>
        <td>long double</td>
        <td>16</td>
        <td>múltiplo de 16</td>
    </tr>
</tbody></table><!--kg-card-end: html--><h3 id="2-preenchimento-de-estruturas">2. Preenchimento de estruturas</h3><p>Talvez você precise inserir alguns bytes extras entre os membros da estrutura para poder alinhar dados. Esses bytes extras são conhecidos como <strong>preenchimento (<em>padding</em>).</strong></p><p>No código acima, os 3 bytes acrescentados foram o preenchimento. Sem este preenchimento, <code>notas[0]</code>, que é de tipo <code>int</code> (endereço múltiplo de 4), teria seu endereço como <code>4225433</code> (não múltiplo de 4).</p><p>Você provavelmente já deve ter percebido por que estruturas não podem ser comparadas diretamente.</p><h3 id="3-alinhamento-de-membro-de-estrutura">3. Alinhamento de membro de estrutura</h3><p>Para explicar este tópico, vamos para outro exemplo (você vai entender o por quê).</p><pre><code class="language-c">struct exemplo
    {
        int i1;
        double d1;
        char c1;
        
    } exemplo1;

void main()
{
    printf("tamanho = %I64d bytes\n",sizeof(exemplo1));
}
</code></pre><p>Qual seria a saída desse programa? Vamos aplicar nossos conhecimentos.</p><p><code>i1</code> possui 4 bytes. Essa variável vai ser seguida de um preenchimento de 4 bytes porque o endereço de <code>d1</code> deve ser divisível por 8.</p><p>Isso será seguido de 8 e 1 byte respectivamente para <code>d1</code> e <code>c1</code>. Logo, a saída deve ser 4 + 4 + 8 + 1 = 17 bytes.</p><pre><code class="language-c"> /* Saída */
tamanho = 24 bytes
</code></pre><p>O quê?! Errado de novo! Por quê? Através de um array de tipo <code>struct exemplo</code>, podemos entender melhor. Também vamos imprimir o endereço dos membros de <code>exemplo2[0]</code>.</p><pre><code class="language-c">void main()
{
    struct exemplo exemplo2[2];
    printf("Endereço de exemplo2[0].i1 = %d\n", &amp;exemplo2[0].i1);
    printf("Endereço de exemplo2[0].d1 = %d\n", &amp;exemplo2[0].d1);
    printf("Endereço de exemplo2[0].c1 = %d\n", &amp;exemplo2[0].c1);

}

 /* Saída */
Endereço de exemplo2[0].i1 = 4225408
Endereço de exemplo2[0].d1= 4225416
Endereço de exemplo2[0].c1 = 4225424
</code></pre><p>Vamos supor que o tamanho de <code>exemplo2[0]</code> é 17 bytes. Isso implica que o endereço de <code>exemplo2[1].i1</code> será <code>4225425</code>. Isso <strong>não é</strong> possível já que o endereço de um <code>int</code> deve ser múltiplo de 4.</p><p>Logicamente, um endereço possível para <code>exemplo2[1].i1</code> pode ser <code>4225428</code>, um múltiplo de 4.</p><p>Isso também está errado. Você sabe o por quê? O endereço de <code>exemplo2[1].d1</code> agora será (28 + 4 (<code>i1</code>) + 3 (preenchimento)) <code>4225436</code>, que não é um múltiplo de 8.</p><p>Para que possamos evitar o desalinhamento, o compilador aplica alinhamento em toda estrutura. Isso é feito ao adicionar bytes extra após o último membro, processo conhecido como <strong>alinhamento de membro de estrutura.</strong></p><p>No exemplo que discutimos no começo desta seção, isso não era necessário (por isso, precisamos de outro exemplo.)</p><p>Uma maneira simples de lembrar deste conceito é por meio desta regra: o endereço e tamanho da estrutura devem ser múltiplos de <code>t_max</code>, onde <code>t_max</code> é o tamanho máximo que um membro da estrutura ocupa.</p><p>No caso de <code>struct exemplo</code>, 8 bytes é o tamanho máximo de <code>d1</code>. Portanto, haverá um preenchimento de 7 bytes no fim da estrutura, fazendo com que seu tamanho seja de 24 bytes.</p><p><strong>Seguindo as duas regras abaixo, você pode facilmente encontrar o tamanho de qualquer estrutura:</strong></p><ol><li>Todo tipo de dado armazena seu valor em um endereço que é múltiplo de seu tamanho.</li><li>Toda estrutura ocupa um tamanho que é múltiplo do tamanho máximo de bytes que um membro ocupa.</li></ol><p>Apesar de sermos capazes de diminuir os ciclos de uma CPU, existe uma quantidade significativa de memória que será desperdiçada.</p><p>Uma maneira de diminuir a quantidade de preenchimento para o mínimo possível é declarando os membros em ordem decrescente de tamanho.</p><p>Se aplicarmos este método em <code>struct exemplo</code>, o tamanho da estrutura é reduzido para 16 bytes. O preenchimento é reduzido de 7 para 3 bytes.</p><pre><code class="language-c">struct exemplo
    {
        double d1; 
        int i1;
        char c1;
        
    } exemplo3;

void main()
{
    printf("tamanho = %I64d bytes\n",sizeof(exemplo3));
}

 /* Saída */
tamanho = 16 bytes
</code></pre><h3 id="4-empacotamento-de-estrutura">4. Empacotamento de estrutura </h3><p>Empacotar (<em>packing</em>) é o oposto de preencher. Empacotar previne o compilador de preencher e remove a memória não alocada.</p><p>No caso do Windows, podemos usar a diretiva <code>#pragma pack</code>, que especifica o empacotamento de membros de estrutura.</p><pre><code class="language-c">#pragma pack(1)

struct exemplo
    {
        double d1; 
        int i1;
        char c1;
        
    } exemplo4;

void main()
{
    printf("tamanho = %I64d bytes\n",sizeof(exemplo4));
}

 /* Saída */
tamanho = 13 bytes
</code></pre><p>Isso garante que os membros da estrutura estejam <em>alinhados</em> em um limite de 1 byte. Em outras palavras, o endereço de qualquer tipo de dado deve ser um múltiplo ou de 1 byte ou do seu tamanho (depende de qual for o menor).</p><h2 id="ponteiros">Ponteiros</h2><blockquote>Se quiser repassar o conteúdo sobre ponteiros antes de seguir em frente com o artigo, aqui está um <a href="https://www.freecodecamp.org/news/pointers-in-c-are-not-as-difficult-as-you-think/">link</a> que cobre ponteiros de maneira aprofundada (texto em inglês).</blockquote><h3 id="1-ponteiro-como-um-membro">1. Ponteiro como um membro</h3><p>Uma estrutura pode ter ponteiros como membros.</p><pre><code class="language-c">struct estudante
    {
        char *nome;
        int *matricula;
        char sexo;
        int notas[5];
    };

void main()
{   int alexMatricula = 44;
   struct estudante estu1 = { "Alex", &amp;alexMatricula, 'M', { 76, 78, 56, 98, 92 }};
}
</code></pre><p>Utilizando o <code>.</code> (operador ponto), podemos novamente acessar os membros. Já que <code>matricula</code> agora tem o endereço de <code>alexMatricula</code>, teremos que desreferenciar <code>estu1.matricula</code> (e não <code>estu1.(*matricula)</code>) para obter o valor</p><pre><code class="language-c"> printf("Nome: %s\n", estu1.nome);
   printf("Matrícula: %d\n", *(estu1.matricula));
   printf("Sexo: %c\n", estu1.sexo);

   for( int i = 0; i &lt; 5; i++)
    printf("Notas na matéria %d: %d\n", i, estu1.notas[i]);

 /* Saída */
Nome: Alex
Matrícula: 43
Sexo: M
Notas na matéria 0: 76
Notas na matéria 1: 78
Notas na matéria 2: 56
Notas na matéria 3: 98
Notas na matéria 4: 92</code></pre><h3 id="2-ponteiro-para-estrutura">2. Ponteiro para estrutura</h3><p>Assim como ponteiros de inteiros, ponteiros de arrays e ponteiros de funções, temos ponteiros para estruturas também.</p><pre><code class="language-c">struct estudante {
    char nome[20];
    int matricula;
    char sexo;
    int notas[5];
};

struct estudante estu1 = {"Alex", 43, 'M', {76, 98, 68, 87, 93}};

struct estudante*ptrEstu1 = &amp;estu1;
</code></pre><p>Declaramos o ponteiro <code>ptrEstu1</code> do tipo <code>struct estudante</code>. Definimos o endereço de <code>estu1</code> para <code>ptrEstu1</code>.</p><p><code>ptrEstu1</code> armazena o endereço base de <code>estu1</code>, que é o endereço base do primeiro membro da estrutura. Incrementar em 1 aumentaria o endereço em <code>sizeof(estu1)</code> bytes.</p><pre><code class="language-c">printf("Endereço da estrutura = %d\n", ptrEstu1);
printf("Endereço do membro `nome` = %d\n", &amp;estu1.nome);
printf("Incrementar em 1 resulta em %d\n", ptrEstu1 + 1);

/* Saída */
Endereço da estrutura = 6421968
Endereço do membro `nome` = 6421968
Incrementar em 1 resulta em 6422016
</code></pre><p>Podemos acessar os membros de <code>estu1</code> usando <code>ptrEstu1</code> de duas formas. Usando <code>*</code> (operador de indireção) ou usando <code>-&gt;</code> (<strong>operador infix ou arrow</strong>).</p><p>Com <code>*</code>, continuaremos usando o <code>.</code> (operador ponto) enquanto que com <code>-&gt;</code> não precisaremos do operador de ponto.</p><pre><code class="language-c">printf("Nome sem usar ptrEstu1 : %s\n", estu1.nome);
printf("Nome usando ptrEstu1 e * : %s\n", (*ptrEstu1).nome);
printf("Nome usando ptrEstu1 e -&gt; : %s\n", ptrEstu1-&gt;nome);

/* Output */
Nome sem usar ptrEstu1 : Alex
Nome usando ptrEstu1 e * : Alex
Nome usando ptrEstu1 e -&gt; : Alex
</code></pre><p>De modo similar, podemos acessar e modificar outros membros também. Note que os parênteses são necessários enquanto utilizamos o <code>*</code> já que o operador de ponto (<code>.</code>) tem procedência maior que <code>*</code>.</p><h3 id="3-ponteiro-e-array-de-estrutura">3. Ponteiro e array de estrutura</h3><!--kg-card-begin: markdown--><p>Podemos criar um array do tipo <code>struct estudante</code> e usar um ponteiro para acessar os elementos e seus membros.</p>
<!--kg-card-end: markdown--><pre><code class="language-c">struct estudante estu[10];

 /* Ponteiro para o primeiro elemento (estrutura) do array */
struct estudante *ptrEstu_tipo1 = estu;

 /* Ponteiro para um array de tamanho 10 do tipo struct estudante */
struct estudante (*ptrEstu_tipo2)[10] = &amp;estu;
</code></pre><p>Note que <code>ptrEstu_tipo1</code> é um ponteiro para <code>estu[0]</code>, enquanto que <code>ptrEstu_tipo2</code> é um ponteiro para o array inteiro de tamanho 10 e tipo <code>struct estudante</code>. Adicionar 1 a <code>ptrEstu_tipo1</code> apontaria para <code>estu[1]</code>.</p><p>Podemos usar <code>ptrEstu_tipo1</code> com um laço de repetição (ou <em>loop</em>) para percorrer os elementos e seus membros.</p><pre><code class="language-c">for( int i = 0; i &lt;  10; i++)
printf("%s, %d\n", ( ptrEstu_tipo1 + i)-&gt;nome, ( ptrEstu_tipo1 + i)-&gt;matricula);
</code></pre><h2 id="fun-es">Funções</h2><h3 id="1-fun-o-como-membro">1. Função como membro</h3><p>Funções <strong>não podem</strong> ser membro de uma estrutura. Contudo, utilizando <em>ponteiros de função</em>, podemos chamar funções utilizando <code>.</code>. Apenas tenha em mente que isso não é recomendado.</p><pre><code class="language-c"> struct exemplo
    {
        int i;
        void (*ptrMensagem)(int i);


    };

void mensagem(int);

void mensagem(int i)
{
    printf("Olá, eu sou um membro de uma estrutura. Esta estrutura também tem um inteiro de valor %d", i);
}

void main()
{
    struct exemplo eg1 = {6, mensagem};
    eg1.ptrMensagem(eg1.i);
}
</code></pre><p>Declaramos dois membros, um inteiro i e um ponteiro de função <code>ptrMensagem</code> dentro de <code>struct exemplo</code>. O ponteiro de função aponta para uma função que recebe um inteiro e retorna <code>void</code>.</p><p><code>mensagem</code> é esta função. Inicializamos <code>eg1</code> com valor <code>6</code> e <code>mensagem</code>. Depois usamos <code>.</code> para chamar a função usando <code>ptrMensagem</code> e passar como valor <code>eg1.i</code>.</p><h3 id="2-estrutura-como-argumento-de-fun-o">2. Estrutura como argumento de função</h3><p>Assim como variáveis, podemos passar <strong>membros individuais de estruturas</strong> como argumentos.</p><pre><code class="language-c">#include &lt;stdio.h&gt;

struct estudante {
    char nome[20];
    int matricula;
    char sexo;
    int notas[5];
};

void display(char a[], int b, char c, int notas[])
{
    printf("Nome: %s\n", a);
    printf("Matrícula: %d\n", b);
    printf("Sexo: %c\n", c);

    for(int i = 0; i &lt; 5; i++)
        printf("Notas na matéria %d: %d\n",i,notas[i]);
}
void main()
{
    struct estudante estu1 = {"Alex", 43, 'M', {76, 98, 68, 87, 93}};
    display(estu1.nome, estu1.matricula, estu1.sexo, estu1.notas);
}

 /* Saída */
Nome: Alex
Matrícula: 43
Sexo: M
Notas na matéria 0: 76
Notas na matéria 1: 98
Notas na matéria 2: 68
Notas na matéria 3: 87
Notas na matéria 4: 93
</code></pre><p>Note que a estrutura <code>struct estudante</code> é declarada dentro de <code>main()</code>, logo no começo. Isto é para assegurar que ela estará disponível globalmente e que <code>display()</code> possa usá-la.</p><p>Se a estrutura for definida dentro de <code>main()</code>, seu escopo estará limitado somente à <code>main()</code>.</p><p>Passar membros de estrutura como argumento não é muito eficiente quando temos um número grande deles. Então, <strong>variáveis de estrutura </strong>podem ser passadas para uma função.</p><pre><code class="language-c">void display(struct estudante a)
{
    printf("Nome: %s\n", a.nome);
    printf("Matrícula: %d\n", a.matricula);
    printf("Sexo: %c\n", a.sexo);

    for(int i = 0; i &lt; 5; i++)
        printf("Notas na matéria %d: %d\n",i,a.notas[i]);
}
void main()
{
    struct estudante estu1 = {"Alex", 43, 'M', {76, 98, 68, 87, 93}};
    display(estu1);
}
</code></pre><p>Se o tamanho da estrutura é muito grande, então passar uma cópia dela será ineficiente. Poderíamos passar um <strong>ponteiro de estrutura</strong> para uma função. Nesse caso, o endereço da estrutura será passado como um argumento de fato.</p><pre><code class="language-c">void display(struct estudante *p)
{
    printf("Nome: %s\n", p-&gt;nome);
    printf("Matrícula: %d\n", p-&gt;matricula);
    printf("Sexo: %c\n", p-&gt;sexo);

    for(int i = 0; i &lt; 5; i++)
        printf("Notas na matéria %d: %d\n",i,p-&gt;notas[i]);
}
void main()
{
    struct estudante estu1 = {"Alex", 43, 'M', {76, 98, 68, 87, 93}};
    struct estudante *ptrEstu1 = &amp;estu1;
    display(ptrEstu1);
}
</code></pre><p>Passar um <strong>array de estrutura</strong> para uma função é semelhante a passar um array de qualquer tipo a uma função. O nome do array, que é o endereço base do array da estrutura, é passado à função.</p><pre><code class="language-c">void display(struct estudante *p)
{   
    for( int j = 0; j &lt; 10; j++)
   {
       printf("Nome: %s\n", (p+j)-&gt;nome);
        printf("Matrícula: %d\n", (p+j)-&gt;matricula);
        printf("Sexo: %c\n", (p+j)-&gt;sexo);

        for(int i = 0; i &lt; 5; i++)
        printf("Notas na matéria %d: %d\n",i,(p+j)-&gt;notas[i]);
   }
}

void main()
{
    struct estudante estu1[10];
    display(estu1);
}
</code></pre><h3 id="3-estrutura-como-retorno-de-fun-o">3. Estrutura como retorno de função</h3><p>Podemos retornar uma <strong>variável de estrutura</strong>, assim como qualquer outra variável.</p><pre><code class="language-c">#include &lt;stdio.h&gt;

struct estudante {
    char nome[20];
    int matricula;
    char sexo;
    int notas[5];
};


struct estudante incrementaEm5(struct estudante p)
{
    for( int i =0; i &lt; 5; i++)
        if(p.notas[i] + 5 &lt;= 100)
           {
               p.notas[i]+=5;
           }
    return p;
}

void main()
{
    struct estudante estu1 = {"Alex", 43, 'M', {76, 98, 68, 87, 93}};
    estu1 = incrementaEm5(estu1);
    
    printf("Nome: %s\n", estu1.nome);
    printf("Matrícula: %d\n", estu1.matricula);
    printf("Sexo: %c\n", estu1.sexo);
    
     for(int i = 0; i &lt; 5; i++)
        printf("Nota na matéria %d: %d\n",i,estu1.notas[i]);
}

 /* Saída */
Nome: Alex
Matrícula: 43
Sexo: M
Notas na matéria 0: 81
Notas na matéria 1: 98
Notas na matéria 2: 73
Notas na matéria 3: 92
Notas na matéria 4: 98
</code></pre><p>A função <code>incrementaEm5()</code> soma 5 à todas as notas de matérias que, após a soma, sejam menores ou iguais a 100. Note que o tipo de retorno é uma variável de estrutura do tipo <code>struct estudante</code>.</p><p>Enquanto retorna um <strong>membro de estrutura</strong>, o tipo de retorno deve ser o mesmo que o do membro.</p><p>Um <strong>ponteiro de estrutura</strong> também pode ser retornado por uma função.</p><pre><code class="language-c">#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;

struct retangulo {
    int tamanho;
    int amplitude;
};

struct retangulo* function(int tamanho, int amplitude)
{
    struct retangulo *p  = (struct retangulo *)malloc(sizeof(struct retangulo));
     p-&gt;tamanho = tamanho;
     p-&gt;amplitude = amplitude;
    return p;
}

void main()
{
    struct retangulo *retangulo1 = function(5,4);
    printf("Tamanho do retangulo = %d unidades\n", retangulo1-&gt;tamanho);
    printf("Amplitude do retangulo = %d unidades\n", retangulo1-&gt;amplitude);
    printf("Área do retangulo = %d unidades quadradas\n", retangulo1-&gt;length * retangulo1-&gt;amplitude);
}

 /* Saída */
Tamanho do retangulo = 5 unidades
Amplitude do retangulo = 4 unidades
Area do retangulo = 20 unidades quadradas</code></pre><p>Note que alocamos a memória de tamanho <code>struct retangulo</code> de forma dinâmica usando <code>malloc()</code>. Já que essa função retorna um ponteiro <em>void</em>, temos que utilizar <em>typecast</em> para transformar este retorno em um ponteiro do tipo <code>struct retangulo</code>.</p><h2 id="estrutura-autorreferencial">Estrutura autorreferencial</h2><p>Vimos que ponteiros podem ser um membro de uma estrutura também. O que ocorre, porém, se o ponteiro for um ponteiro de estrutura? O ponteiro pode ser tanto <strong>do mesmo tipo da estrutura </strong>ou<strong> diferente.</strong></p><p>Estruturas autorreferenciais são aquelas que possuem ponteiro(s) de estrutura do mesmo tipo do seu(s) membro(s).</p><pre><code class="language-c">struct estudante {
    char nome[20];
    int matricula;
    char sexo;
    int notas[5];
    struct estudante *next;
 };</code></pre><p>Essa é uma estrutura autorreferencial onde <code>next</code> é um ponteiro de estrutura do tipo <code>struct estudante</code>.</p><p>Agora, vamos criar duas estruturas de variáveis <code>estu1</code> e <code>estu2</code> e inicializá-las. Depois, vamos armazenar o endereço de <code>estu2</code> no membro <code>next</code> de <code>estu1</code>.</p><pre><code class="language-c">void main()
{
    struct estudante estu1 = {"Alex", 43, 'M', {76, 98, 68, 87, 93}, NULL};
    struct estudante estu2 = { "Max", 33, 'M', {87, 84, 82, 96, 78}, NULL};
    estu1.next = &amp;estu2;
}
</code></pre><p>Isso nos permite acessar os membros de <code>estu2</code> usando <code>estu1</code> e <code>next</code>.</p><pre><code class="language-c">void main()
{
    printf("Nome: %s\n", estu1.next-&gt;nome);
    printf("Matrícula: %d\n", estu1.next-&gt;matricula);
    printf("Sexo: %c\n", estu1.next-&gt;sexo);

    for(int i = 0; i &lt; 5; i++)
        printf("Notas na matéria %d: %d\n",i,estu1.next-&gt;notas[i]);
}

 /* Saída */
Nome: Max
Matrícula: 33
Sexo: M
Notas na matéria 0: 87
Notas na matéria 1: 84
Notas na matéria 2: 82
Notas na matéria 3: 96
Notas na matéria 4: 78
</code></pre><p>Suponha que queremos uma estrutura de variável diferente após <code>stu1</code>, ou seja, <em>inserir outra estrutura de variável entre <code>estu1</code> e <code>estu2</code></em>. Isso pode ser feito facilmente.</p><pre><code class="language-c">void main()
{
    struct estudante estuBetween = { "Gasly", 23, 'M', {83, 64, 88, 79, 91}, NULL};
    est1.next = &amp;estuBetween;
    estuBetween.next = &amp;estu2;
}
</code></pre><p>Agora <code>estu1.next</code> armazena o endereço de <code>estuBetween</code>. E <code>estuBetween.next</code> tem o endereço de <code>estu2</code>. Podemos, agora, acessar todas as três estruturas usando <code>estu1</code>.</p><pre><code class="language-c">  printf("Matrícula de %s: %d\n", estu1.next-&gt;nome, estu1.next-&gt;matricula);
    printf("Sexo de %s: %c\n", estu1.next-&gt;next-&gt;nome, estu1.next-&gt;next-&gt;sexo);

 /* Saída */
Matrícula de Gasly: 23
Sexo de Max: M</code></pre><p>Note como formamos uma ligação entre <code>estu1</code>, <code>estuBetween</code> e <code>estu3</code>. O que discutimos aqui foi o começo de uma <strong>Lista Ligada</strong> (<em>Linked List</em>)</p><p>Estruturas autorreferenciais são muito úteis na criação de estruturas de dados como a própria <em>lista ligada, pilhas, filas, grafos e daí por diante.</em></p><h2 id="conclus-o">Conclusão</h2><p>Feito! Abordamos tudo, desde a definição do que é uma estrutura, até o uso de estruturas autorreferenciais.</p><p>Tente revisar todos os subtópicos que você ler. Se conseguir lembrá-los, parabéns! Leia os que não conseguir lembrar novamente.</p><p>O próximo passo lógico seria aprender mais sobre listas ligadas e outras várias estruturas de dados que foram usadas aqui.</p><p>Continue aprendendo.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Coletor de lixo em Java – o que é coleta de lixo e como ela funciona na JVM ]]>
                </title>
                <description>
                    <![CDATA[ Em um artigo anterior [https://www.freecodecamp.org/news/jvm-tutorial-java-virtual-machine-architecture-explained-for-beginners/]  (em inglês), escrevi sobre a Máquina Virtual do Java (JVM) e expliquei sua arquitetura. Como parte do componente de ferramenta de execução, eu também falei brevemente sobre o Coletor de Lixo do Java (em inglês, Garbage Collector, ou GC ). Neste artigo, você vai ]]>
                </description>
                <link>https://www.freecodecamp.org/portuguese/news/coletor-de-lixo-em-java-o-que-e-a-coleta-de-lixo-e-como-ela-funciona-na-jvm/</link>
                <guid isPermaLink="false">6475361826662f059b14ab97</guid>
                
                    <category>
                        <![CDATA[ Java ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Nathalia Nóbrega ]]>
                </dc:creator>
                <pubDate>Wed, 21 Jun 2023 21:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/GC.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artigo original:</strong> <a href="https://www.freecodecamp.org/news/garbage-collection-in-java-what-is-gc-and-how-it-works-in-the-jvm/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Garbage Collection in Java – What is GC and How it Works in the JVM</a>
      </p><p>Em um <a href="https://www.freecodecamp.org/news/jvm-tutorial-java-virtual-machine-architecture-explained-for-beginners/">artigo anterior</a> (em inglês), escrevi sobre a Máquina Virtual do Java (JVM) e expliquei sua arquitetura. Como parte do componente de ferramenta de execução, eu também falei brevemente sobre o Coletor de Lixo do Java (em inglês, <em>Garbage Collector, ou GC</em>).</p><p>Neste artigo, você vai aprender mais sobre o <em>Garbage Collector</em>, como ele funciona, os tipos variados de GC presentes no Java e suas vantagens. Também comentarei alguns dos novos Coletores de Lixo experimentais que estão disponíveis nas últimas versões do Java.</p><h2 id="o-que-a-coleta-de-lixo-em-java"><strong>O que é a coleta de lixo em Java?</strong></h2><p>A coleta de lixo é o processo de recolher a memória não utilizada em tempo de execução, destruindo os objetos inutilizados.</p><p>Em linguagens como C e C++, o programador é responsável tanto pela criação quanto pela destruição dos objetos. Às vezes, o programador pode esquecer de destruir objetos que não estão sendo utilizados. A memória alocada para eles, por isso, não é liberada. A memória utilizada pelo sistema continua crescendo e, em algum momento, não haverá memória disponível no sistema para alocar seus objetos. O nome dado a tal processo é "<em>memory leak</em>" (vazamento de memória).</p><p>Após um certo ponto, a memória suficiente não se encontra disponível para a criação de objetos. O programa inteiro, então, finaliza anormalmente devido a um erro do tipo <em>OutOfMemoryError</em>.</p><p>Você pode usar métodos como free() em C e delete() em C++ para realizar operações de coleta de lixo. Em Java, porém, a coleta de lixo acontece automaticamente durante o ciclo de vida de um programa. Isso elimina a necessidade de desalocar memória e, portanto, evita vazamentos de memória.</p><p>O <em>Garbage Collector</em> do Java é o processo no qual os programas em Java realizam o gerenciamento automático de memória. Programas em Java são compilados em <em>bytecode</em>, podendo ser executados na Máquina Virtual do Java (<em>Java Virtual Machine</em>).</p><p>Quando estes programas são executados na JVM, objetos são criados na memória <em>heap</em>, que é a porção da memória dedicada ao programa.</p><p>No decorrer do ciclo de vida de uma aplicação em Java, objetos são criados e dispensados. Ao final, alguns objetos não são mais necessários. É possível dizer que, a qualquer ponto, a memória <em>heap</em> consiste em dois tipos de objetos:</p><ul><li><em>Vivos (Live)</em> – estes objetos estão sendo utilizados e referenciados em algum lugar</li><li><em>Mortos (Dead)</em> – estes objetos não estão sendo utilizados ou não estão sendo referenciados em lugar algum.</li></ul><p>O coletor de lixo encontra esses objetos que não estão sendo utilizados e os exclui para salvar memória.</p><h2 id="como-desreferenciar-um-objeto-em-java">Como desreferenciar um objeto em Java</h2><p>O objetivo principal do coletor de lixo é salvar espaço na memória <em>heap </em>por meio da destruição de objetos que não contêm uma referência. Quando não existem referências a um objeto, a JVM pressupõe que o mesmo está morto (dead) e que não é mais necessário. Então, a memória <em>heap </em>ocupada por este objeto pode ser desocupada.</p><p>Existem diversas formas pelas quais as referências de um objeto podem ser desfeitas para transformá-lo em um candidato à coleta de lixo. Algumas delas são:</p><h3 id="transformar-uma-refer-ncia-em-nula">Transformar uma referência em nula</h3><pre><code class="language-java">Estudante estudante = new Estudante();
estudante = null;</code></pre><h3 id="atribuir-uma-refer-ncia-outra">Atribuir uma referência à outra</h3><pre><code class="language-java">Estudante estudanteUm = new Estudante();
Estudante estudanteDois = new Estudante();
estudanteUm = estudanteDois; // agora o primeiro objeto referenciado por estudanteUm está disponível para garbage collection</code></pre><h3 id="utilizar-um-objeto-an-nimo">Utilizar um objeto anônimo</h3><pre><code class="language-java">registrar(new Estudante());</code></pre><h2 id="como-funciona-o-garbage-collection-em-java">Como funciona o Garbage Collection em Java?</h2><p>O Garbage Collection do Java é um processo automático. O programador não precisa marcar explicitamente os objetos a serem excluídos.</p><p>A implementação da coleta de lixo se encontra na JVM (Máquina Virtual do Java). Cada JVM pode implementar sua própria versão de <em>Garbage Collection</em>. Porém, essa versão deve atender aos padrões da especificação da JVM de trabalhar com objetos presentes na memória <em>heap</em>, marcar ou identificar os objetos inalcançáveis, e destruí-los com compactação.</p><h2 id="o-que-s-o-as-roots-de-garbage-collection-em-java">O que são as <em>roots</em> de Garbage Collection em Java?</h2><p>Coletores de lixo funcionam sob o conceito de <em>Garbage Collection Roots</em> (GC Roots) para identificar objetos vivos e mortos.</p><p>Exemplos dessas <em>roots </em>de <em>Garbage Collection</em> são:</p><ul><li>Classes executadas pelo executor de classes do sistema (com exceção dos executores de classes customizadas)</li><li>Threads ativas</li><li>Variáveis locais e parâmetros dos métodos em execução</li><li>Variáveis locais e parâmetros de métodos JNI (<em>Java Native Interface</em>)</li><li>Referências globais de JNI</li><li>Objetos utilizados como monitores para sincronização</li><li>Objetos mantidos da coleta de lixo pela JVM para seus fins</li></ul><p>O coletor de lixo percorre todo o grafo de objetos na memória, começando pelas <em>roots </em>de <em>Garbage Collection</em> e referências posteriores às <em>roots</em> de outros objetos.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/image-76.png" class="kg-image" alt="image-76" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/image-76.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2023/06/image-76.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/image-76.png 1372w" sizes="(min-width: 720px) 720px" width="1372" height="1183" loading="lazy"></figure><h2 id="etapas-de-coleta-de-lixo-em-java">Etapas de coleta de lixo em Java</h2><p>Uma implementação padrão de coletor de lixo envolve três etapas:</p><h3 id="marcar-objetos-como-vivos">Marcar objetos como vivos</h3><p>Nessa etapa, o GC identifica todos os objetos vivos na memória ao percorrer o grafo de objetos.</p><p>Quando o GC "visita" um objeto, o marca como acessível – logo, ele está vivo. Todo objeto que o GC visita é marcado como vivo. Todos os objetos que não podem ser visitados pelas <em>roots </em>do GC são lixo e considerados como candidatos para coleta.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/image-82.png" class="kg-image" alt="image-82" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/image-82.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2023/06/image-82.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1600/2023/06/image-82.png 1600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/image-82.png 1613w" sizes="(min-width: 720px) 720px" width="1613" height="294" loading="lazy"></figure><h3 id="se-livrar-de-objetos-mortos">Se livrar de objetos mortos</h3><p>Após a fase de marcação, temos um espaço na memória que é ocupado tanto por objetos vivos (<em>visited</em>), quanto por objetos mortos (<em>unvisited</em>). A fase de "livração" libera fragmentos de memória que contêm objetos mortos.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/image-83.png" class="kg-image" alt="image-83" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/image-83.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2023/06/image-83.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1600/2023/06/image-83.png 1600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/image-83.png 1613w" sizes="(min-width: 720px) 720px" width="1613" height="294" loading="lazy"></figure><h3 id="compactar-os-objetos-restantes-na-mem-ria">Compactar os objetos restantes na memória</h3><p>Os objetos mortos que são removidos durante a fase de liberação não precisam necessariamente estar um ao lado do outro. Portanto, você pode acabar tendo espaços de memória fragmentados.</p><p>A memória, então, pode ser compactada depois que o coletor de lixo excluir os objetos mortos, para que os objetos remanescentes estejam em um bloco contíguo no começo da memória <em>heap</em>.</p><p>O processo de compactação faz com que seja mais fácil alocar memória para novos objetos de forma sequencial.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/image-85.png" class="kg-image" alt="image-85" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/image-85.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2023/06/image-85.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1600/2023/06/image-85.png 1600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/image-85.png 1613w" sizes="(min-width: 720px) 720px" width="1613" height="294" loading="lazy"></figure><h2 id="o-que-a-coleta-de-lixo-geracional-em-java">O que é a coleta de lixo geracional em Java?</h2><p>Os coletores de lixo em Java implementam uma estratégia chamada coleta de lixo geracional, que categoriza objetos por idade.</p><p>Ter que marcar e compactar todos os objetos em uma JVM é ineficiente. Quanto mais e mais objetos são alocados, a lista de objetos cresce, levando a um tempo de coleta mais longo. A análise empírica de aplicações têm mostrado que a maioria dos objetos em Java têm vida curta.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/ObjectLifetime.gif" class="kg-image" alt="ObjectLifetime" width="742" height="513" loading="lazy"><figcaption>Fonte: oracle.com</figcaption></figure><p>No exemplo acima, o eixo Y representa o número de bytes alocados. O eixo X representa o tempo. Como você pode ver, menos e menos objetos permanecem alocados com o passar do tempo.</p><p>Na verdade, a maioria dos objetos têm uma vida muito curta, como foi demonstrado pelos altos valores no lado esquerdo do gráfico. É por isso que o Java categoriza e realiza coleta de lixo de acordo com as gerações de objetos.</p><p>A área da memória <em>heap </em>na JVM é dividida em três seções:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/image-70.png" class="kg-image" alt="image-70" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/image-70.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2023/06/image-70.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1600/2023/06/image-70.png 1600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w2400/2023/06/image-70.png 2400w" sizes="(min-width: 1200px) 1200px" width="2860" height="987" loading="lazy"></figure><h2 id="gera-o-jovem">Geração jovem</h2><p>Objetos recentemente criados começam na geração jovem (<em>Young Generation</em>). Esta geração é subdividida em:</p><ul><li><strong>Espaço Éden</strong> (EdenSpace) – todos os novos objetos começam aqui, e a memória inicial é alocada neles.</li><li><strong>Espaço de sobreviventes</strong> (FromSpace e ToSpace) – objetos são movidos daqui para o Éden após um ciclo de coleta.</li></ul><p>Quando objetos são coletados a partir da Geração Jovem, é um <em>evento menor de coleta de lixo.</em></p><p>Quando o Espaço Éden é preenchido por objetos, um evento menor de Garbage Collection é realizado. Todos os objetos mortos são excluídos e todos os objetos vivos são movidos para um dos Espaços de sobreviventes. &nbsp;Coletas de lixo menores também verificam os objetos em um espaço de sobreviventes e os movem para outro espaço.</p><p>Tenha a seguinte sequência como exemplo:</p><ol><li>O Éden tem todos os objetos (vivos e mortos)</li><li>Uma Coleta de Lixo menor ocorre – todos os objetos mortos são removidos do Éden. Todos os objetos vivos são movidos para o S1 (FromSpace). O Éden e o S2 agora estão vazios.</li><li>Objetos são criados e adicionados ao Éden. Alguns objetos neste espaço e no S1 se tornam mortos.</li><li>Outro evento menor de GC ocorre – todos os objetos mortos são removidos do Éden e do S1. Todos os objetos vivos são movidos para o S2 (ToSpace). Eden e S1 agora estão vazios.</li></ol><p>Portanto, em qualquer momento, um dos espaços de sobreviventes está vazio. Quando os objetos sobreviventes alcançam uma certa "experiência" em serem movidos entre os espaços de sobreviventes diversas vezes, eles são transferidos à Geração Velha.</p><p>Você pode usar a flag `-Xmn` para definir o tamanho da Geração Jovem.</p><h2 id="gera-o-velha">Geração velha</h2><p>Objetos que são mais velhos são eventualmente movidos da Geração Jovem para a Geração Velha (<em>Old Generation</em>). Esta geração também é referenciada como <em>Tenured Generation</em>, e contêm objetos que continuaram nos espaços de sobreviventes por um longo tempo.</p><p>Há um limite definido para a promoção de um objeto que decide quantos ciclos de coleta de lixo ele pode sobreviver antes de ser movido para a Geração Antiga.</p><p>Quando objetos são coletados da Geração Antiga, chamamos de evento maior de coleta de lixo.</p><p>Você pode usar as <em>flags </em><code>-Xms</code> e <code>-Xmx</code> para determinar o tamanho inicial e máximo da memória <em>heap</em>.</p><p>Já que o Java utiliza coleta de lixo geracional, quanto mais eventos de coleta um objeto sobrevive, mais ele é promovido na <em>heap</em>. Ele começa na Geração Jovem e eventualmente termina na <em>Tenured Generation</em> se conseguir sobreviver por tempo suficiente.</p><p>Considere o seguinte exemplo para entender a promoção de objetos entre espaços e gerações:</p><p>Quando um objeto é criado, ele primeiro fica alocado no <strong>Espaço Éden</strong> da <strong>Geração Jovem</strong>. Quando um evento menor de coleta de lixo ocorre, os objetos vivos são promovidos ao <strong>FromSpace</strong>. Quando um novo evento menor ocorre, tanto os objetos vivos do <strong>Éden</strong> e do <strong>FromSpace</strong> são movidos para o <strong>ToSpace</strong>.</p><p>Este ciclo continua por um número específico de vezes. Se o objeto continuar sendo referenciado até esse ponto, o próximo ciclo de coleta de &nbsp;lixo vai movê-lo para o espaço da Geração Antiga.</p><h2 id="gera-o-permanente">Geração permanente</h2><p>Metadados de classes e métodos são alocados na Geração Permanente (<em>Permanent Generation</em>). Ela é utilizada pela JVM durante o tempo de execução com base nas classes em uso pela aplicação. Classes que não estão mais em uso nesta Geração podem ser coletadas pelo <em>Garbage Collector</em>.</p><p>Você pode usar as flags <code>-XX:PermGen</code> e <code>-XX:MaxPermGen</code> para determinar o tamanho inicial e máximo da <em>Permanent Generation</em>.</p><h2 id="metaspace">MetaSpace</h2><p>A partir do Java 8, o espaço de memória <strong>MetaSpace</strong> substituiu o espaço <strong>PermGen</strong>. A implementação difere da PermGen, e este espaço da Heap agora é redimensionado automaticamente.</p><p>Isso evita o problema de aplicações ficarem sem memória devido ao tamanho limite do espaço PermGen da memória <em>Heap</em>. A memória <em>MetaSpace</em> pode ser coletada e as classes que não estão mais em uso podem ser automaticamente coletadas quando o MetaSpace alcança seu tamanho limite.</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.49999999999999%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="113" src="https://www.youtube.com/embed/X1DkoRGVRp4?start=1&amp;feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" title="Garbage Collection in Java | What is GC and How it Works in JAVA | Part One" name="fitvid0"></iframe>
          </div>
        </div>
      </figure><h2 id="tipos-de-garbage-collector-na-m-quina-virtual-do-java">Tipos de Garbage Collector na Máquina Virtual do Java</h2><p>A coleta de lixo faz com que o Java seja uma linguagem eficiente no quesito de uso de memória porque remove os objetos sem referência da memória <em>heap </em>e libera espaço para novos objetos.</p><p>A Máquina Virtual do Java tem oito tipos de coletores de lixo. Vamos conhecer cada um deles com mais detalhe.</p><h2 id="gc-serial">GC serial</h2><p>Esta é a implementação mais simples do <em>Garbage Collector </em>e foi feita para aplicações pequenas que estão sendo executadas em ambientes <em>single-threaded</em>. Todos os eventos de coleta de lixo são conduzidos em série em uma <em>thread</em>. A compactação da memória é executada após cada coleta.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/image-68.png" class="kg-image" alt="image-68" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/image-68.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2023/06/image-68.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1600/2023/06/image-68.png 1600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/image-68.png 1686w" sizes="(min-width: 720px) 720px" width="1686" height="647" loading="lazy"></figure><p>Quando a aplicação é executada, ocorre um evento "<em>stop the world</em>" (pare o mundo) onde toda a aplicação é pausada. Já que a aplicação inteira é congelada durante a coleta de lixo, o GC serial não é recomendado em aplicações de larga escala, onde a latência baixa é uma necessidade.</p><p>O argumento da JVM para utilizar o Garbage Collector serial é <code>-XX:+UeSerialGC</code>.</p><h2 id="gc-paralelo">GC paralelo</h2><p>O coletor paralelo é feito para aplicações com conjuntos de dados de médio a largo porte que rodam em multiprocessadores ou hardware <em>multi-threaded</em>. Essa é a implementação padrão do <em>Garbage Collector</em> da JVM e também é conhecida como <em>Throughput Collector</em>.</p><p>Múltiplas <em>threads </em>são utilizadas para um evento menor de coleta de lixo na Geração Jovem. Uma única <em>thread </em>é utilizada para eventos maiores de coleta na Geração Velha.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/image-66.png" class="kg-image" alt="image-66" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/image-66.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2023/06/image-66.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1600/2023/06/image-66.png 1600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/image-66.png 1686w" sizes="(min-width: 720px) 720px" width="1686" height="647" loading="lazy"></figure><p>Executar o GC paralelo também ocasiona o evento "<em>stop the world</em>" e a aplicação é pausada. Já que esta implementação é mais apropriada em um ambiente <em>multi-threaded</em>, ela pode ser usada quando muitas atividades são feitas e pausas longas são aceitáveis, como, por exemplo, executar uma tarefa em lote.</p><p>O argumento na JVM para executar o GC paralelo é <code>-XX:+UseParallelGC</code>.</p><h2 id="gc-paralelo-antigo">GC paralelo antigo</h2><p>Essa é a versão padrão do GC paralelo desde o Java 7u4. É a mesma implementação do GC paralelo, exceto pelo fato de utilizar <em>threads </em>múltiplas tanto para a Geração Jovem quanto para a Velha.</p><p>O argumento na JVM para executar o <em>Garbage Collector </em>paralelo antigo é <code>-XX:+UseParallelOldGC</code>.</p><h2 id="gc-cms-concurrent-mark-sweep-">GC CMS (Concurrent Mark Sweep)</h2><p>Essa implementação também é conhecida como o coletor de pausa baixa simultânea. Múltiplas <em>threads </em>são usadas como coletas de lixo menores usando o mesmo algoritmo do paralelo. Coletas de lixo maiores são <em>multi-threaded</em>, como no GC paralelo antigo, mas o CSM roda de forma simultânea aos processos da aplicação para minimizar os eventos "<em>stop the world</em>".</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/image-67.png" class="kg-image" alt="image-67" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/image-67.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2023/06/image-67.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1600/2023/06/image-67.png 1600w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/image-67.png 1686w" sizes="(min-width: 720px) 720px" width="1686" height="647" loading="lazy"></figure><p>Por causa disso, o coletor CSM usa mais CPU do que as outras implementações de GC. Se você pode alocar mais CPU em prol de melhor desempenho, o CMS é uma escolha melhor que o paralelo. Não há compactação nesta implementação.</p><p>O argumento na JVM para usar o <em>Garbage Collector</em> de <em>Concurrent Mark Sweep</em> (em português, algo como "varredura de marca concorrente") é <code>-XX:+UseConcMarkSweepGC</code>.</p><h2 id="gc-g1-garbage-first-">GC G1 (Garbage First)</h2><p>O G1GC tinha a intenção de substituir o CMS e foi criado para aplicações <em>multi-threaded</em> que possuem um tamanho grande de memória <em>heap </em>disponível (acima de 4GB). É implementado de modo paralelo e simultânea, como o CMS, mas funciona de maneira um pouco diferente debaixo dos panos em comparação com os <em>garbage collectors </em>anteriores.</p><p>Apesar do G1 também ser geracional, ele não separa espaços para as gerações Jovem e Velha. Na verdade, cada geração é um conjunto de espaços, o que permite alterar o tamanho da Geração Jovem de modo flexível.</p><p>Ele particiona a <em>heap </em>em um conjunto de espaços de tamanhos iguais (1MB a 32MB - dependendo do tamanho da <em>heap</em>) e utiliza múltiplas <em>threads </em>para as escanear. Uma região pode ser Velha ou Jovem em qualquer período de tempo durante a execução do programa.</p><p>Após o período de marcação ser completo, o G1 sabe quais espaços contêm mais objetos que precisam ser coletados. Se o usuário está interessado em tempos de pausa mínimos, o G1 pode escolher evacuar apenas alguns espaços. Se o usuário não se preocupa com isso ou definiu um tempo de pausa grande, o G1 pode escolher incluir mais espaços.</p><p>Já que o G1CC identifica os espaços com a maior quantidade de lixo e realiza a coleta naqueles espaços primeiro, ele é chamado de Garbage First (lixo primeiro).</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/image-88.png" class="kg-image" alt="image-88" srcset="https://www.freecodecamp.org/portuguese/news/content/images/size/w600/2023/06/image-88.png 600w, https://www.freecodecamp.org/portuguese/news/content/images/size/w1000/2023/06/image-88.png 1000w, https://www.freecodecamp.org/portuguese/news/content/images/2023/06/image-88.png 1445w" sizes="(min-width: 720px) 720px" width="1445" height="985" loading="lazy"></figure><p>Além dos espaços de memória Eden, Sobreviventes e Velho, existem mais dois tipos de espaços presentes no G1CC:</p><ul><li><em>Humongous (Enorme) – usado para objetos grandes (maiores que 50% do tamanho da </em>heap<em>)</em></li><li><em>Available (Disponíveis) – usado para espaços não utilizados ou não alocados.</em></li></ul><p>O argumento na JVM para usar o <em>Garbage Collector</em> G1 é <code>-XX:+UseG1GC</code> .</p><h2 id="garbage-collector-epsilon">Garbage Collector Epsilon</h2><p>O Epsilon é um coletor de lixo "do-nothing" (que "não faz nada") que foi lançado como parte da JDK 11. Ele gerencia a alocação de memória, mas não implementa nenhum mecanismo de aproveitamento de memória. Uma vez que a memória <em>heap </em>disponível está cheia, a JVM para de funcionar.</p><p>Ele pode ser usado para aplicações que são sensíveis a latências extremas, onde os desenvolvedores sabem o <em>footprint</em> exato da memória da aplicação, ou até mesmo possuem aplicações que são (quase) <em>garbage-free</em> (livres de lixo). A utilização do GC Epsilon em qualquer outro cenário é desencorajado.</p><p>O argumento na JVM para utilizar o <em>Garbage Collector</em> Epsilon é <code>-XX:+UnlockExperimentalVMOptions -XX:+UseEpsilonGC</code>.</p><h2 id="shenandoah">Shenandoah</h2><p>O Shenandoah é um GC novo que foi lançado como parte do JDK 12. A sua vantagem principal sobre o <em>Garbage Collector</em> G1 é que ele realiza mais ciclos de coleta de lixo de maneira simultânea às <em>threads </em>da aplicação. O G1 pode evacuar seus espaços na <em>heap </em>apenas quando a aplicação é pausada, enquanto o Shenandoah pode realocar objetos simultaneamente com a aplicação.</p><p>Shenandoah pode compactar objetos vivos, coletar o lixo e mandar RAM de volta ao sistema operacional quase imediatamente após detectar memória livre. Já que tudo isso ocorre simultaneamente enquanto a aplicação roda, o Shenandoah é mais intensivo no quesito do uso de CPU.</p><p>O argumento na JVM para utilizar o <em>Garbage Collector</em> Shenandoah é <code>-XX:+UnlockExperimentalVMOptions -XX:+UseShenandoahGC</code>.</p><h2 id="zgc">ZGC</h2><p>O ZGC é outro <em>Garbage Collector</em> que foi lançado como parte da JDK 11 e foi melhorado na JDK 12. Ele foi criado para aplicações que requerem baixa latência (pausas de menos de 10ms) e/ou que utilizam um grande espaço da memória <em>heap</em> (multi-terabytes).</p><p>Os principais objetivos do ZGC são a baixa latência, escalabilidade e facilidade de uso. Para alcançar isso, o ZGC permite que uma aplicação em Java continue rodando enquanto ele executa todas as operações de <em>Garbage Collection</em>. Por padrão, o ZGC libera a memória não utilizada e a retorna ao sistema operacional.</p><p>Logo, o ZGC traz uma melhora significativa sobre outros <em>Garbage Collectors</em> tradicionais ao prover tempos de pausa extremamente baixos (tipicamente dentro de 2ms).</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/figure2_600w.jpg" class="kg-image" alt="figure2_600w" srcset="https://www.freecodecamp.org/portuguese/news/content/images/2023/06/figure2_600w.jpg 600w" width="600" height="525" loading="lazy"><figcaption>Fonte: oracle.com</figcaption></figure><p>O argumento na JVM para utilizar o <em>Garbage Collector </em>Shenandoah é <code>-XX:+UnlockExperimentalVMOptions -XX:+UseZGC</code>.</p><p><strong>Observação:</strong> tanto o Shanandoah quanto o ZGC estão sob planos de passarem a ser <em>features </em>de produção e serem removidos do estágio de experimentação na JDK 15.</p><h2 id="como-escolher-o-garbage-collector-certo">Como escolher o <em>Garbage Collector </em>certo?</h2><p>Se a sua aplicação não tem tempos de pausa estritos, você deve somente rodar a sua aplicação e deixar a JVM escolher o coletor certo para você.</p><p>Na maior parte do tempo, as configurações padrão devem funcionar bem. Se necessário, você pode ajustar o tamanho da <em>heap </em>para melhorar o desempenho. Se o desempenho ainda não alcançar suas expectativas, você pode alterar o coletor de lixo padrão de acordo com as necessidades do seu projeto:</p><ul><li><strong>Serial</strong> – se a aplicação tem um conjunto de dados pequeno (aproximadamente 100MB) e/ou vai rodar em um único processador sem ter requisitos de tempo de pausa.</li><li><strong>Paralelo</strong> – se o melhor desempenho da aplicação for a prioridade e não houver requisitos para tempos de pausa ou pausas de um segundo ou mais serão aceitáveis.</li><li><strong>CMS/G1</strong> – se o tempo de resposta é mais importante que a taxa de processamento e as pausas de coleta de lixo devem ser mantidas abaixo de aproximadamente um segundo.</li><li><strong>ZGC</strong> – se o tempo de resposta for a prioridade maior, e/ou você está usando grande parte da <em>heap</em>.</li></ul><h2 id="vantagens-do-garbage-collection">Vantagens do <em>Garbage Collection</em></h2><p>Existem múltiplos benefícios da coleta de lixo em Java.</p><p>Primeiramente, ela deixa o seu código mais simples. Você não precisa se preocupar com a alocação correta de memória e ciclos de liberação. Você para de usar um objeto no seu código e a memória que ele utiliza vai ser automaticamente liberada em algum momento.</p><p>Programadores que trabalham em linguagens sem <em>Garbage Collection </em>(como C e C++) devem implementar gerenciamento de memória manual em seus códigos.</p><p>Este processo também faz com que o Java seja eficiente em termos de memória, pois o coletor de lixo remove os objetos não referenciados da memória <em>heap</em>. Isso libera espaço na <em>heap </em>para acomodar novos objetos.</p><p>Enquanto alguns programadores argumentam em favor do gerenciamento de memória manual ao invés de <em>Garbage Collection</em>, o GC é agora um componente padrão em diversas linguagens de programação populares.</p><p>Para cenários onde o <em>Garbage Collector</em> impacta negativamente o desempenho, o Java oferece diversas opções para melhorar sua eficiência.</p><h2 id="melhores-pr-ticas-de-garbage-collection">Melhores práticas de <em>Garbage Collection</em></h2><h3 id="evite-disparos-manuais">Evite disparos manuais</h3><p>Além dos mecanismos básicos de coleta de lixo, um dos pontos mais importantes para entender a respeito de <em>Garbage Collection </em>no Java é que ele não é determinístico. Isso significa que não tem como prever quando a coleta de lixo vai ocorrer durante o tempo de execução.</p><p>É possível incluir uma sugestão à JVM no seu código para que ela inicie o coletor de lixo com os métodos <code>System.gc()</code> ou <code>Runtime.gc()</code>, mas isso não dá garantia de que o coletor realmente vai ser executado.</p><h3 id="utilize-ferramentas-de-an-lise">Utilize ferramentas de análise</h3><p>Se você não tem memória suficiente para rodar sua aplicação, você vai lidar com problemas de lentidão, um longo período de coleta de lixo, eventos "<em>stop the world</em>" e, por fim, erros do tipo <em>out of memory.</em> Isso pode indicar que o tamanho da sua <em>heap </em>é muito pequeno, mas também que você pode ter um vazamento de memória na sua aplicação.</p><p>Você pode ter o auxílio de uma ferramenta de monitoramento como o <code>jstat</code> ou <em>Java Flight Recorder</em> para analisar se o uso da memória <em>heap </em>cresce indefinidamente, o que pode indicar um bug no seu código.</p><h3 id="configura-es-padr-o-s-o-suas-amigas">Configurações padrão são suas amigas</h3><p>Se você estiver executando uma aplicação Java pequena e independente, você muito provavelmente não precisa alterar as configurações do <em>Garbage Collector</em>. As configurações padrão devem dar conta do trabalho.</p><h3 id="utilize-flags-na-jvm-para-ajustes">Utilize <em>flags </em>na JVM para ajustes</h3><p>A melhor forma de ajustar a <em>Garbage Collection</em> de acordo com as suas necessidades é utilizando <em>flags </em>na JVM. <em>Flags </em>podem configurar o GC que vai ser utilizado (Serial, G1 ou outros), o tamanho inicial e máximo da memória <em>heap</em>, o tamanho dos espaços da <em>heap </em>(Geração Jovem, Velha) e muito mais.</p><h3 id="escolha-o-coletor-apropriado">Escolha o coletor apropriado</h3><p>A natureza da aplicação que está passando por ajustes é um guia inicial muito eficiente para as configurações do coletor. Por exemplo, o GC paralelo é eficiente, mas vai causar eventos "<em>stop the world</em>" frequentes, fazendo com que ele seja mais apropriado para processamento em back-end, onde as longas pausas para coleta de lixo são aceitáveis.</p><p>Por outro lado, o Garbage Collector CMS foi criado para minimizar pausas, sendo ideal para aplicações baseadas na Web, onde a responsividade é importante.</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.49999999999999%;" class="fluid-width-video-wrapper">
            <iframe width="200" height="113" src="https://www.youtube.com/embed/4sBhc-pSILs?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" title="Garbage Collection in Java | Types of Garbage Collectors in JAVA | Part Two" name="fitvid1"></iframe>
          </div>
        </div>
      </figure><h2 id="conclus-o">Conclusão</h2><p>Neste artigo, discutimos <em>Garbage Collection</em> em Java, como funciona e seus diferentes tipos.</p><p>Para muitas aplicações simples, <em>Garbage Collection</em> não é algo que um programador Java precise considerar. Contudo, para programadores que querem melhorar suas habilidades em Java, é importante entender como esse processo funciona.</p><p>Este conceito também é muito popular em entrevistas técnicas, tanto para cargos de back-end júnior, quanto sênior.</p><p>Agradecemos por sua companhia até aqui. Esperamos que tenha gostado do artigo. Você pode se conectar com o autor pelo <a href="https://www.linkedin.com/in/theawesomenayak/">LinkedIn</a>, onde ele fala regularmente sobre assuntos como tecnologia e a vida. Dê uma olhada também em <a href="https://www.freecodecamp.org/news/author/theawesomenayak/">outros artigos do autor</a> (em inglês) e no <a href="https://www.youtube.com/channel/UCmWAaPgfWAkl-Jep5mY-NNg?sub_confirmation=1">canal do autor no YouTube</a>. Boa leitura. 🙂️</p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
