Como fazer benchmarking e medir a performance de código Java?

O benchmarking em Java permite medir a eficiência do código, analisando tempo de execução, uso de CPU e memória para otimização.

Como fazer benchmarking e medir a performance de código Java?

Medir a performance do código Java é essencial para otimizar a execução e identificar gargalos de desempenho. Para isso, podemos utilizar técnicas de benchmarking e ferramentas específicas.

1. Método simples: System.nanoTime()

Podemos medir o tempo de execução de um código com System.nanoTime():

public class Benchmarking {
    public static void main(String[] args) {
        long inicio = System.nanoTime();

        int soma = 0;
        for (int i = 0; i < 1_000_000; i++) {
            soma += i;
        }

        long fim = System.nanoTime();
        System.out.println("Tempo de execução: " + (fim - inicio) / 1_000_000 + " ms");
    }
}

Explicação:

  • nanoTime() oferece maior precisão que currentTimeMillis().
  • Divide por 1_000_000 para converter para milissegundos.

2. Benchmarking avançado com JMH (Java Microbenchmark Harness)

O JMH (Java Microbenchmark Harness) é uma ferramenta oficial do Java para medir performance de forma precisa.

Passo 1: Adicionar dependência do JMH

Se estiver usando Maven, adicione ao pom.xml:

<dependencies>
    <dependency>
        <groupId>org.openjdk.jmh</groupId>
        <artifactId>jmh-core</artifactId>
        <version>1.35</version>
    </dependency>
    <dependency>
        <groupId>org.openjdk.jmh</groupId>
        <artifactId>jmh-generator-annprocess</artifactId>
        <version>1.35</version>
    </dependency>
</dependencies>

Passo 2: Criar um benchmark com JMH

import org.openjdk.jmh.annotations.*;
import java.util.concurrent.TimeUnit;

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@State(Scope.Thread)
public class MeuBenchmark {

    @Benchmark
    public int calcularSoma() {
        int soma = 0;
        for (int i = 0; i < 1_000_000; i++) {
            soma += i;
        }
        return soma;
    }
}

Explicação:

  • @Benchmark marca o método a ser testado.
  • @BenchmarkMode(Mode.AverageTime) mede o tempo médio de execução.
  • @OutputTimeUnit(TimeUnit.MILLISECONDS) define a unidade de tempo.
  • Para rodar, utilize mvn clean install e java -jar target/benchmarks.jar.

3. Medindo consumo de CPU e memória com VisualVM

O VisualVM permite monitorar uso de CPU, memória e garbage collector:

  1. Instale o VisualVM (Download ).
  2. Inicie sua aplicação Java normalmente.
  3. Abra o VisualVM e selecione seu processo.
  4. Analise uso de CPU, memória alocada e threads em execução.

4. Identificando gargalos de desempenho

✔️ Evite loops desnecessários: Reduza iterações sempre que possível. ✔️ Use estruturas de dados eficientes: Prefira ArrayList em vez de LinkedList quando for mais vantajoso. ✔️ Evite sincronia excessiva: Bloqueios desnecessários podem impactar a performance. ✔️ Faça profiling da aplicação: Ferramentas como VisualVM ajudam a identificar métodos mais lentos.

Conclusão

Medir e otimizar a performance do código Java é essencial para aplicações de alto desempenho. Ferramentas como JMH, VisualVM e System.nanoTime() ajudam a identificar gargalos e otimizar a eficiência do código.

Benchmarking é fundamental para avaliar a eficiência de um código antes da otimização. Em aplicações reais, saber onde estão os gargalos permite que desenvolvedores façam melhorias direcionadas e evitem desperdício de recursos computacionais.

Algumas aplicações:

  • Avaliação de tempo de execução de algoritmos
  • Monitoramento de consumo de CPU e memória
  • Otimização de código para alto desempenho
  • Comparação de diferentes abordagens de implementação

Dicas para quem está começando

  • Use System.nanoTime() para medições rápidas
  • Experimente o JMH para benchmarks mais precisos
  • Monitore CPU e memória com VisualVM
  • Evite otimizar código sem medir sua real necessidade

Contribuições de Rodrigo Farias

Compartilhe este tutorial: Como fazer benchmarking e medir a performance de código Java

Compartilhe este tutorial

Continue aprendendo:

O que é ForkJoinPool e quando usá-lo

ForkJoinPool é um pool de threads otimizado para tarefas paralelizáveis, permitindo dividir grandes problemas em subtarefas menores.

Tutorial anterior

Como usar ThreadLocal para armazenar dados de forma isolada

ThreadLocal permite que cada thread tenha uma cópia isolada de um dado, evitando concorrência e melhorando o isolamento de informações.

Próximo tutorial