Garbage Collection (GC): o que é, algoritmos e coleta de lixo no desenvolvimento mobile

Autor: IT Sectr Publicado: 2026-03-29 Tempo de leitura: 10 min

O gerenciamento automático de memória através da coleta de lixo é um mecanismo chave da plataforma Android, baseado na máquina virtual ART. De acordo com Google Android Documentation, 2026, o coletor de lixo libera o desenvolvedor do gerenciamento manual de memória, removendo automaticamente objetos que não têm mais referências. Sem GC, cada alocação de objeto exigiria uma chamada explícita a free ou delete, o que no ecossistema Java com milhões de objetos por segundo é fisicamente impossível.

Pontos principais

  • Garbage Collection — mecanismo automático de liberação de memória removendo objetos não utilizados em Java e Android
  • Algoritmos básicos — Mark-and-Sweep, Copying Collection e Generational Collection determinam a eficiência da coleta
  • ART e Dalvik — duas implementações da máquina virtual Android, onde ART (Android Runtime) substituiu Dalvik a partir do Android 5.0
  • Pausas de GC — paradas da execução da aplicação durante a coleta — principal causa de jank e problemas de desempenho
  • Otimização de GC — redução de alocações, uso de pools de objetos e escolha correta dos tipos de coleta reduzem a carga do coletor

O que é Garbage Collection (GC)?

Garbage Collection (GC) é um processo automático de detecção e liberação de memória ocupada por objetos que não são mais usados pelo programa. No contexto do desenvolvimento mobile, o GC é usado na plataforma Android através da máquina virtual ART, bem como na Java Virtual Machine padrão.

Ao contrário de linguagens com gerenciamento manual de memória (C, C++), onde o programador deve chamar explicitamente free ou delete, o GC assume completamente a tarefa de rastrear o ciclo de vida dos objetos. O desenvolvedor cria novos objetos através do operador new, enquanto o coletor determina quando um objeto se torna inalcançável — ou seja, quando não restam referências ativas a ele.

As principais métricas de eficiência do GC são o tempo de pausa (pause time) e a taxa de transferência (throughput). A pausa é o período durante o qual a execução da aplicação é interrompida para realizar a coleta. Em um ambiente mobile, pausas superiores a 8–16 milissegundos são perceptíveis como quadros perdidos (jank).

De acordo com o Google I/O 2019, o ART no Android 10 reduziu as pausas típicas de GC para 2–4 ms, o que representa 70% menos em comparação com o Dalvik no Android 4.4. No entanto, o gerenciamento inadequado de memória — alocação frequente de objetos em loops, criação de instâncias temporárias desnecessárias — continua sendo a principal causa de problemas de desempenho.

Como funciona o coletor de lixo: algoritmos básicos

Todas as implementações de GC em Java e Android baseiam-se em vários algoritmos fundamentais que são combinados para alcançar um equilíbrio entre tempo de pausa e completeza da limpeza. Compreender esses algoritmos é essencial para escrever código amigável ao GC.

Mark-and-Sweep

Mark-and-Sweep é o algoritmo mais simples, funcionando em duas etapas. Na fase de Mark, o coletor percorre o grafo de objetos começando pelas referências raiz (root set) — variáveis locais, campos estáticos, pilhas de threads. Cada objeto alcançável é marcado com um sinalizador de vivo. Na fase de Sweep, o coletor percorre todo o heap e libera a memória dos objetos não marcados.

A desvantagem é a fragmentação da memória: após o Sweep, as áreas livres alternam-se com as ocupadas, dificultando a alocação de objetos grandes. Em cenários mobile, isso é crítico, pois o heap geralmente é pequeno (64–512 MB no Android).

Copying Collection

Copying Collection divide o heap em dois semiespaços (semi-spaces). Objetos ativos são copiados compactamente de um semiespaço para o outro, sem lacunas. Após a cópia, o semiespaço antigo é declarado completamente livre. O algoritmo elimina totalmente a fragmentação, mas requer o dobro de memória.

Em ambientes mobile, o Copying Collection é usado por coletores geracionais para limpeza rápida de objetos jovens, que estatisticamente morrem cedo (hipótese geracional fraca).

Generational Collection

Generational Collection divide o heap em gerações: Young Generation (objetos jovens) e Old Generation (objetos velhos que sobreviveram a várias coletas). A coleta da geração jovem (Minor GC) é realizada com frequência e rapidez, pois a maioria dos objetos morre jovem. A coleta da geração velha (Major GC ou Full GC) ocorre com menos frequência, mas dura mais tempo.

java
// Demonstração de GC geracional: objetos jovens morrem rápido
void processItems(List<Item> items) {
    List<Result> results = new ArrayList<>();       // vive durante todo o método
    for (Item item : items) {
        Result r = new Result(item.getValue());    // morre instantaneamente
        if (r.isValid()) {
            process(r);                               // r torna-se lixo
        }
    }
    saveResults(results);                             // results passa para Old Gen
}

Neste exemplo, objetos Result são criados dentro de um loop e tornam-se imediatamente lixo — são candidatos ideais para Young GC. O objeto results vive mais tempo e migra para Old Generation. A separação de gerações permite que o Minor GC limpe objetos jovens em milissegundos sem tocar no heap antigo.

Garbage Collection no Android: ART e Dalvik

O Android evoluiu de Dalvik VM para ART (Android Runtime), e a implementação do GC é uma das principais diferenças entre eles. Compreender a arquitetura do GC no Android ajuda a escrever código que minimize as pausas em dispositivos reais.

CaracterísticaDalvik (até 4.4)ART (5.0+)
Tipo de GCMark-and-Sweep com Concurrent MarkGeneracional + Concorrente
Pausa típica10–30 ms2–4 ms
CompactaçãoNão (apenas a fragmentação cresce)Sim (em segundo plano, sem parar o app)
Compilação AOTJIT (Just-In-Time)AOT + JIT (híbrido)

Dalvik GC

Dalvik usava uma combinação de Mark-and-Sweep com uma fase concorrente. O Concurrent Mark permitia que a aplicação continuasse funcionando durante a travessia do grafo de objetos, mas a fase Sweep exigia a parada de todas as threads (Stop-The-World). Em dispositivos com pouca RAM (512 MB — 1 GB), as pausas atingiam 30 ms, causando atrasos perceptíveis na interface. Além disso, o Dalvik não compactava o heap, portanto, após uso prolongado, a fragmentação aumentava e a alocação de objetos grandes (por exemplo, Bitmap) podia lançar OutOfMemoryError mesmo com memória livre total suficiente.

ART GC

ART (Android Runtime) introduziu um coletor geracional com compactação concorrente. O heap é dividido em três regiões: Young, Mature (análogo à Old Generation) e Large Object Space (para objetos maiores que 12 KB). A coleta da região Young ocorre em paralelo sem parar as threads na maioria dos casos. No Android 10+, foi introduzido o Concurrent Copying — a compactação é executada em uma thread de fundo sem Stop-The-World.

Graças à arquitetura do ART, as pausas típicas de GC foram reduzidas para 2–4 ms, e em cenários com predominância de objetos jovens — para 0.5–1 ms. Isso permitiu que dispositivos Android mantivessem 60 FPS estáveis mesmo durante operações ativas de memória.

Tipos de coletores de lixo em Java

No ecossistema Java, existem várias implementações de GC, cada uma com seu próprio perfil de desempenho. Para o desenvolvimento Android, a escolha é limitada ao ART, mas o conhecimento do Java GC é útil ao escrever código do lado do servidor para aplicações mobile e ao desenvolver com Kotlin Multiplatform.

Serial GC

Serial GC é um coletor de thread única com parada completa da aplicação (Stop-The-World). Cada operação Mark, Sweep e Compact é realizada por uma thread. O desempenho é baixo — não é usado para servidores mobile. Adequado apenas para aplicações pequenas com heap de até 100 MB.

Parallel GC

Parallel GC (também conhecido como Throughput Collector) usa múltiplas threads para todas as fases de coleta. É orientado para a máxima taxa de transferência (throughput) — minimizando o tempo gasto em GC em relação ao tempo de execução da aplicação. Ativado através da flag -XX:+UseParallelGC na JVM.

G1 GC

G1 (Garbage-First) GC é o coletor padrão no Java 9+. O heap é dividido em regiões de 1–32 MB. O G1 prevê o tempo de pausa e se esforça para permanecer dentro do limite especificado (padrão 200 ms). Prioridade: regiões com maior quantidade de lixo são limpas primeiro (daí o nome). O G1 é eficaz para servidores com grandes heaps (4–64 GB) com pausas previsíveis.

java
// Ativando G1 GC com pausa alvo de 100 ms
// java -XX:+UseG1GC -XX:MaxGCPauseMillis=100 -jar app.jar

public class MemoryMonitor {
    private static final long THRESHOLD = 512 * 1024 * 1024; // 512 MB

    public void checkHeapUsage() {
        Runtime rt = Runtime.getRuntime();
        long used = rt.totalMemory() - rt.freeMemory();
        if (used > THRESHOLD) {
            System.out.println("Heap usage exceeded threshold: " + used);
            System.out.println("Consider reducing allocations");
        }
    }
}

Monitorar o heap via Runtime permite detectar vazamentos de memória em estágio inicial. Se used exceder 80% do heap máximo em operação estável — isso é um sinal de possível vazamento ou consumo excessivo de memória pela aplicação.

Problemas de GC e otimização de memória em aplicações mobile

Mesmo o ART GC moderno não resolve todos os problemas — o uso inadequado de memória continua sendo a principal causa de jank e ANR (Application Not Responding). Vamos examinar os principais cenários e métodos de otimização.

Pausas de GC e Jank

Pausas de GC — paradas das threads da aplicação durante a coleta. Na tela, isso se manifesta como quadros perdidos, quando o tempo entre dois quadros excede 16.6 ms (60 FPS). Se o GC durar 30 ms, apenas um quadro é desenhado em vez de dois — o usuário vê travamentos na interface.

As principais causas de pausas longas: grande número de objetos vivos na Old Generation, fragmentação do heap, Full GC frequente. Para diagnóstico, são usados Android Studio Profiler e systrace.

Redução da carga de GC

A regra principal do código amigável ao GC é minimizar o número de objetos alocados. Cada novo objeto requer não apenas alocação de memória, mas também coleta subsequente. Mesmo que o GC seja rápido, 1000 alocações extras por segundo resultam em 1000 verificações para o coletor.

  • Evite criar objetos em loops — mova a criação para fora do loop, reutilize variáveis locais
  • Use pools de objetos — para Bitmap, byte[] e outras estruturas pesadas, use Object Pool ou RecyclerView.ViewHolder
  • Prefira primitivos — int em vez de Integer, float em vez de Float evitam autoboxing
  • Use SparseArray — em vez de HashMap<Integer, V>, o Android SDK oferece SparseArray, LongSparseArray que trabalham com primitivos
  • StringBuilder em vez de concatenação — cada soma de strings cria um novo objeto String

Vazamentos de memória

Um vazamento de memória ocorre quando um objeto permanece alcançável mesmo não sendo mais necessário. O GC não pode excluir tal objeto e a memória se esgota gradualmente. Causas típicas: listeners não removidos, referências estáticas a Activity, classes anônimas capturando contexto externo e Cursor/InputStream não fechados.

java
// Vazamento de memória: classe anônima mantém referência à Activity
public void startTask() {
    new Thread(new Runnable() {                    // mantém implicitamente this (Activity)
        @Override
        public void run() {
            // operação longa...
            System.out.println("Done");
        }
    }).start();
}

// Correção: classe estática aninhada + WeakReference
private static class TaskRunnable implements Runnable {
    private WeakReference<Activity> activityRef;

    TaskRunnable(Activity activity) {
        this.activityRef = new WeakReference<>(activity);
    }

    @Override
    public void run() {
        Activity act = activityRef.get();
        if (act != null) {
            // trabalho seguro com Activity
        }
    }
}

Neste exemplo, o Runnable anônimo captura uma referência implícita à Activity. Enquanto a thread estiver viva — a Activity não pode ser coletada pelo GC, mesmo que o usuário já tenha fechado a tela. A correção com WeakReference + classe estática quebra essa corrente e permite que a Activity seja liberada.

Perguntas frequentes

Como o GC no Android difere do GC em Java?

GC no Android (ART) é um coletor geracional com compactação concorrente, otimizado para dispositivos mobile com memória limitada. Java GC (G1, ZGC) são coletores do lado do servidor com grandes heaps e pausas previsíveis. ART GC não usa flags da JVM — toda a configuração é feita automaticamente no nível do SO.

O que é Stop-The-World no GC?

Stop-The-World é o momento em que o coletor pausa todas as threads da aplicação para percorrer o grafo de objetos ou liberar memória com segurança. Quanto mais longo o STW, mais perceptível é o jank. O ART reduziu o tempo típico de STW para 2–4 ms graças à sua arquitetura geracional.

Como detectar um vazamento de memória no Android?

Use o Android Studio Memory Profiler — ele mostra o crescimento do heap, a quantidade de alocações e permite fazer Heap Dump. Para análise aprofundada, use LeakCanary — a biblioteca detecta automaticamente vazamentos e mostra a cadeia de referências que impede a coleta do GC.

Quando ocorre o Full GC e por que é perigoso?

Full GC é uma coleta completa de todas as gerações do heap, incluindo a Old Generation. Em aplicações mobile, o Full GC pode durar 50–200 ms, causando jank ou ANR perceptíveis. Principais causas: fragmentação do heap, vazamentos de memória, exceder o limite da Old Generation.

Como o Kotlin ajuda a evitar vazamentos de memória?

Kotlin fornece corrotinas com concorrência estruturada — o cancelamento do escopo cancela automaticamente todas as corrotinas filhas, prevenindo vazamentos. Kotlin também tem o delegado lazy para inicialização preguiçosa e funções de escopo que reduzem o número de objetos temporários.

Resumo

  • Garbage Collection — gerenciamento automático de memória removendo objetos inalcançáveis, base do Android Runtime
  • Mark-and-Sweep — algoritmo básico com coleta de duas fases, sofre de fragmentação de heap
  • Copying Collection — elimina a fragmentação copiando objetos vivos para um semiespaço compacto
  • Generational GC — divide o heap em gerações (Young/Old), acelerando a coleta de objetos jovens de curta duração
  • ART no Android — coletor geracional com compactação concorrente e pausas de 2–4 ms, substituiu o Dalvik no Android 5.0
  • Otimização de GC — redução de alocações, pools de objetos, primitivos em vez de wrappers e SparseArray em vez de HashMap reduzem a carga do coletor
  • Diagnóstico — Android Studio Profiler, systrace e LeakCanary são as principais ferramentas para identificar problemas de memória

Vamos desenvolver um aplicativo móvel chave na mão

A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.

Discutir o projeto

Leia também