Lentidão no desenvolvimento — o que é, causas e métodos de otimização

Autor: IT Sectr Publicado: 2026-07-28 Tempo de leitura: 8 min

Lentidão é a descrição do usuário para uma situação em que um aplicativo móvel funciona de forma lenta e irregular: às vezes responde normalmente, às vezes trava repentinamente por alguns segundos. No contexto técnico, “lentidão” significa uma combinação de lag e microtravamentos causados por pausas frequentes do GC, bloqueio da thread principal por operações síncronas e estruturas de dados subótimas. De acordo com o Android Performance Benchmarking Guide, reduzir o tempo de resposta de 300 ms para 100 ms aumenta a retenção de usuários em 25%. Diagnosticar a lentidão requer uma combinação de perfilamento de CPU e Memória com análise da frequência de coleta de lixo.

Principais pontos

  • Lentidão é uma desaceleração intermitente do aplicativo, alternando com desempenho normal
  • Principais causas — pausas frequentes do GC, operações síncronas na thread de UI, grande volume de dados em adaptadores sem paginação
  • Diagnóstico requer CPU Profiler para encontrar gargalos e Memory Profiler para analisar frequência e duração do GC
  • Solução inclui implementar paginação (Paging 3), otimizar consultas SQL via Room e descarregar tarefas pesadas para o WorkManager
  • Prevenção — Benchmark Baseline Profiles, compilação AOT, minimizar alocações em caminhos de código quentes

O que significa “lentidão” no desenvolvimento móvel

Lentidão é um termo informal que os usuários usam para descrever um desempenho subjetivamente lento do aplicativo. Ao contrário de um lag, que se manifesta como um atraso constante, a lentidão consiste em travamentos irregulares: o aplicativo pode funcionar perfeitamente por vários segundos e então “pensar” por 1–3 segundos.

Descrição técnica do fenômeno

Da perspectiva de perfilamento, lentidão se manifesta como uma série de quadros perdidos (jank) com picos de atraso acima de 100 ms. Em um gráfico de FPS, isso parece quedas bruscas: 60 → 20 → 55 → 10 quadros por segundo. Ao contrário de um lag com FPS uniformemente baixo, a lentidão tem variabilidade pronunciada.

Percepção do usuário

Quando um aplicativo está lento, o usuário não entende a lógica das desacelerações: a tela pode rolar suavemente e então parar repentinamente por um segundo. Isso causa frustração e reduz a confiança no aplicativo. Segundo o Google, 53% dos usuários abandonam um site ou aplicativo se o carregamento demorar mais de 3 segundos.

Causas de desacelerações repentinas em aplicativos

A natureza intermitente da lentidão indica que o problema é causado por fatores baseados em eventos, não por sobrecarga constante. Vamos examinar os cenários típicos.

Pausas do GC durante alocação de objetos

No Android, no ambiente ART, a coleta de lixo para todas as threads do aplicativo. Se o código cria muitos objetos temporários — por exemplo, criando uma nova String via concatenação a cada chamada onBindViewHolder — o GC é executado com mais frequência. Uma pausa pode durar 5–50 ms dependendo do tamanho do heap e da geração de objetos. O usuário percebe isso como “pensatividade” repentina.

Consultas SQL síncronas na thread de UI

Room no Android e Core Data no iOS suportam consultas assíncronas, mas os desenvolvedores frequentemente chamam getValue() ou executam consultas via runBlocking por simplicidade. Um SELECT pesado com joins em uma tabela de 10.000 linhas pode levar 200–500 ms, bloqueando completamente a UI durante esse tempo.

Decodificação de imagem sem redimensionamento

Carregar uma imagem de câmera (12 MP, 4000x3000 px) sem redimensionamento leva até 200 ms para decodificar em Bitmap. Se as imagens são carregadas assincronamente mas sem um pool de threads limitado, executar 5–6 decodificações simultâneas pode sobrecarregar a CPU, causando lentidões migratórias.

  • Android — concatenação de strings em loops, criação de objetos em caminhos críticos, Bitmap sem inSampleSize
  • iOS — pools de autorelease com muitos objetos, imageWithContentsOfFile sem redimensionamento, URLSession síncrona
  • Multiplataforma — parsing JSON na thread de UI, carregamento de dados na thread principal enquanto aguarda resposta do servidor

Como diagnosticar travamentos no Android e iOS

Diagnosticar lentidões intermitentes é mais difícil que diagnosticar lags constantes porque o problema pode não se reproduzir em toda execução. É necessária coleta de estatísticas por um longo período.

Memory Profiler com gravação de eventos GC

Android Studio Memory Profiler mostra não apenas o uso de memória, mas também eventos GC: frequência, tipo (Concurrent, Full), duração. Se o GC ocorre mais de uma vez a cada 5 segundos em estado ocioso — é um sinal de alocação excessiva. Fazer um heap dump no momento da lentidão revela quais objetos estão ocupando memória.

Xcode Instruments com Allocation Tracking

No iOS, use o template Allocations no Instruments para rastrear criação e liberação de objetos. Ative Generations — elas permitem tirar snapshots do heap entre ações e ver quais objetos permanecem na memória. Objetos persistentes que não são liberados são fonte de acúmulo de memória e pausas subsequentes.

API JankStats no Android

JankStats é uma biblioteca Android que coleta métricas de quadros perdidos em tempo real. Ela associa cada jank ao cenário atual (por exemplo, “rolagem de lista”, “abertura de tela”), permitindo entender qual ação específica desencadeia a lentidão.

Exemplo de integração do JankStats para rastrear travamentos no Android:

kotlin
class MainActivity : AppCompatActivity() {
    private lateinit var jankStats: JankStats

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        jankStats = JankStats.create(this.window.decorView) { frameData ->
            if (frameData.isJank()) {
                Log.w("Jank", "Duration=${frameData.durationMs}ms")
            }
        }
    }
}

Métodos para eliminar o desempenho lento

Eliminar a lentidão requer trabalho direcionado em cada causa. Não existe solução universal — é necessária análise de perfis de desempenho específicos.

Implementação de paginação via Paging 3

Se uma lista contém 1000+ itens e todos são carregados de uma vez — isso é lentidão garantida. Paging 3 no Android e NSFetchedResultsController no iOS carregam dados em porções conforme o usuário rola. O usuário vê apenas os primeiros 10–20 itens; o restante é carregado em segundo plano.

Otimização de consultas SQL e índices

Room permite perfilar consultas através da Ferramenta de Inspeção no Android Studio: tempo de execução, número de linhas retornadas e plano de consulta são visíveis. Adicionar índices nas colunas WHERE e ORDER BY pode reduzir o tempo de consulta de 300 ms para 5 ms. No iOS, uma verificação semelhante é realizada pelo Core Data Profiler no Instruments.

Descarregamento de tarefas para o WorkManager

Sincronizações em segundo plano, downloads de arquivos, processamento de dados — tudo isso deve ser executado via WorkManager (Android) ou Background Tasks (iOS). Se a sincronização roda na thread de UI, o aplicativo ficará lento durante a execução. O WorkManager garante execução em uma thread de segundo plano com ciência do estado da bateria e rede.

Exemplo de sincronização em segundo plano via WorkManager no Android:

kotlin
class SyncWorker(context: Context, params: WorkerParameters)
    : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result {
        return try {
            Log.d("Sync", "Syncing data in background thread")
            syncData()
            Result.success()
        } catch (e: Exception) {
            Result.retry()
        }
    }
}

Prevenção de lentidão na fase de desenvolvimento

A lentidão pode ser prevenida na fase de codificação seguindo os princípios de gerenciamento eficiente de memória e threads.

Baseline Profiles para compilação AOT

Baseline Profiles são uma lista de classes e métodos que o Android compila antecipadamente (AOT) em vez de JIT. Sem um perfil, cada nova tela é compilada ao abrir pela primeira vez, causando um atraso de 100–500 ms. Prepare um Baseline Profile para as telas principais e ative a geração no Gradle através do baseline-profile-gradle-plugin.

Minimização de alocações em caminhos críticos

Um caminho crítico é o código executado em cada quadro: onBindViewHolder, draw, layoutSubviews. Evite criar objetos nestes métodos: use pools de objetos, StringBuilder em vez de concatenação, armazene em cache strings formatadas e formatadores. Cada alocação extra aproxima o próximo GC.

Perfilamento via Baseline Profiles no CI

Adicione Macrobenchmark ao seu pipeline de CI com um cenário de rolagem de lista e abertura de tela. Defina um limite: o percentil 99 do tempo de quadro não deve exceder 16 ms. Se o limite for excedido — a compilação é rejeitada até otimização.

  • Android — Baseline Profiles, Macrobenchmark, JankStats, StrictMode com penaltyDeath
  • iOS — MetricKit, os_signpost, XCTMetric, Main Thread Checker no esquema Debug
  • Abordagem geral — perfilamento regular, revisões de código focadas em alocações em caminhos críticos

Perguntas frequentes

Como a lentidão difere de um lag normal?

Um lag é um atraso constante (por exemplo, 200 ms em cada toque). Lentidão é intermitente: o aplicativo funciona normalmente, então repentinamente desacelera por 1–3 segundos, depois volta ao normal. A causa são fatores baseados em eventos como pausas do GC ou consultas síncronas ao banco de dados.

Como medir a frequência de pausas do GC no Android?

Use Memory Profiler no Android Studio: a aba Memory mostra eventos GC com duração. Para monitoramento em produção, integre Firebase Performance Monitoring com traces personalizados. No iOS, ative Malloc Debug e marque gerações de alocação no Instruments.

Requisições de rede podem causar lentidão?

Indiretamente — sim. Se a resposta do servidor atrasa e a UI espera sincronamente, o aplicativo trava. Se a requisição é assíncrona mas o processamento da resposta é feito na thread de UI — isso também causará lentidão. A solução é processamento assíncrono com corrotinas e indicadores de progresso.

Como o Kotlin Multiplatform afeta o desempenho?

Quando usado incorretamente, KMP pode gerar objetos wrapper excessivos para interoperabilidade. No iOS, isso aumenta a frequência de alocações e, consequentemente, as pausas do ARC. Use @ObjCName, otimize expect/actual e evite chamadas frequentes ao código compartilhado a partir de caminhos críticos da UI.

Aumentar o tamanho do heap no Android ajuda?

Aumentar o heap via android:largeHeap=”true” atrasa o GC mas não elimina a causa das alocações. Quando o GC finalmente é executado, a pausa será mais longa porque mais objetos precisam ser percorridos. A solução é reduzir o número de alocações, não expandir o heap.

Resumo

  • Lentidão é uma desaceleração intermitente do aplicativo causada por fatores baseados em eventos (pausas GC, consultas síncronas, decodificação de imagem)
  • Diagnóstico requer Memory Profiler, JankStats no Android e Allocation Tracking no Instruments no iOS
  • Principais causas — pausas frequentes do GC, falta de paginação, consultas SQL subótimas e processamento síncrono na thread de UI
  • Solução — Paging 3, WorkManager, otimização de índices de BD, redimensionamento de imagem e minimização de alocações
  • Prevenção — Baseline Profiles, Macrobenchmark, StrictMode, revisões de código com verificação de caminhos críticos
  • Ferramentas — JankStats, Firebase Performance, MetricKit para monitoramento de lentidão em produção
  • Recomendação: implemente execuções regulares de Macrobenchmark no CI com limite de 16 ms no percentil 99 dos quadros

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