Perfilando código Java: encontrando gargalos na prática
Todo desenvolvedor Java, mais cedo ou mais tarde, enfrenta problemas de desempenho: a aplicação roda lentamente, consome muita memória ou "congela" inesperadamente. Nessas situações, o perfilamento é indispensável. Neste artigo, vamos explorar como encontrar gargalos no código Java na prática, usando ferramentas modernas de perfilamento.
O que é perfilamento e por que ele é necessário?
Perfilamento (profiling) é uma análise dinâmica do programa que coleta dados sobre seu funcionamento: uso de CPU, consumo de memória, tempo de execução de métodos, quantidade de objetos criados e threads. Diferente da registro de logs, o perfilamento fornece uma imagem precisa dos "gargalos" sem a necessidade de ajustar temporizadores manualmente.
Principais tipos de perfilamento:
- Perfilamento de CPU — determina quais métodos consomem mais tempo de processador.
- Perfilamento de memória — identifica vazamentos de memória, frequência de criação de objetos e funcionamento do coletor de lixo (GC).
- Perfilamento de threads — analisa bloqueios, deadlocks e estado das threads.
Ferramentas para perfilamento Java
Vamos analisar três ferramentas populares que ajudarão você a encontrar gargalos.
1. VisualVM
Ferramenta gratuita incluída no JDK. Ideal para análise rápida de uma aplicação em execução. Permite monitorar CPU, memória, threads e até realizar dumps de heap.
// Iniciar VisualVM pela linha de comandojvisualvm.exe2. JProfiler
Profiler comercial com um conjunto poderoso de recursos: análise detalhada de CPU, memória, JDBC, JPA e consultas SQL. Ideal para aplicações enterprise.
3. Java Flight Recorder (JFR) + JDK Mission Control
Ferramenta integrada à JVM (disponível desde o Java 11). Coleta eventos de baixo nível sem impacto significativo no desempenho. Recomendado para ambientes de produção.
// Gravação JFR por 60 segundosjcmd <PID> JFR.start duration=60s filename=recording.jfrExemplo prático: encontrando um gargalo
Suponha que temos uma aplicação que processa uma lista de usuários e gera relatórios. Ela está lenta. Vamos escrever um código de teste simples e perfilá-lo com o VisualVM.
Passo 1. Preparação do código
import java.util.ArrayList;import java.util.List;
public class SlowApp { public static void main(String[] args) { List<String> users = new ArrayList<>(); for (int i = 0; i < 100000; i++) { users.add("User" + i); } processUsers(users); }
public static void processUsers(List<String> users) { for (String user : users) { String report = generateReport(user); // Simulação de salvamento System.out.println(report.length()); } }
public static String generateReport(String user) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < 1000; i++) { sb.append(user).append(" - data ").append(i).append(""); } return sb.toString(); }}Passo 2. Iniciar o perfilamento
Execute a aplicação e abra o VisualVM. Selecione o processo no painel esquerdo, vá para a aba "Profiler" e clique em "CPU" para iniciar o perfilamento.
Passo 3. Análise dos resultados
Após parar o perfilamento, você verá uma tabela com os métodos ordenados pelo tempo gasto. No nosso exemplo, o método generateReport estará no topo — ele consome mais de 90% do tempo de CPU devido à concatenação de strings no loop.
Passo 4. Otimização
Vamos substituir o StringBuilder por um buffer pré-alocado:
Blogs
Book Recommendations
Leia também