Material de suporte rápido para conhecer e setar parâmetros de JVM mais comuns relacionados a propriedades da JVM, configuração de frameworks e libs, aplicação e tuning de memória heap e metaspace, além da definição do algoritimo de GC e algumas configurações para troubleshooting.
Todos os comandos aqui são executados via linha de comando, mas podem ser definidos na sua IDE, variável de ambiente (JAVA_OPTS
) ou no seu servidor de integração contínua (CI).
Rodando uma aplicação (jar):
java -jar app.jar
Rodando uma aplicação com argumentos de aplicação:
java -jar calculadora.jar "somar" 1 2 # resultado=3
Passando propriedades de JVM para aplicação:
java -Duser.timezone=America/Sao_Paulo -jar app.jar # novo fuso horário: São Paulo
Passando propriedades especificas de frameworks para aplicação:
java -Dserver.port=8083 -jar app.jar # porta do servidor web no Spring Boot 2.x
Passando propriedades especificas de negócio para aplicação:
java -Dhabilita.logs=true -jar app.jar # propriedade "habilita.logs" será utilizada pela app
Executando uma aplicação Java sem informar parâmetros de memória:
java -jar app.jar # tuning de memória baseado na máquina
Ao executar uma aplicação Java sem informar parâmetros de memória, a JVM vai fazer o self-tuning de acordo com as configurações da máquina (ou container) hospedeira. Ou seja, a JVM vai olhar para CPU, quantidade de cores, RAM da máquina, arquitetura 32 ou 64bits etc para só então definir a quantidade de memória para Heap, Metaspace etc. Essa feature é conhecida como Ergonomics.
Passando parâmetros de memória Heap da JVM para aplicação via linha de comando:
java -Xms256m -Xmx512m -jar app.jar # heap.inicial=256mb; heap.maxima=512mb
Passando parâmetros de memória Metaspace da JVM para aplicação via linha de comando:
java -XX:MaxMetaspaceSize=2048m -jar app.jar # metaspace.maxima=2gb
Passando parâmetros de memória da JVM para aplicação via linha de comando:
java -Xms256m -Xmx512m -XX:MaxMetaspaceSize=2048m -jar app.jar
Definindo o algoritimo de GC utilizado pela JVM:
java -jar app.jar # usa GC default do java
java -XX:+UseG1GC -jar app.jar # G1 eh default a partir do java 9
java -XX:+UseParallelGC -jar app.jar # Parallel GC eh default no java 8
java -XX:+UseZGC -jar app.jar # define Z GC na JVM
Habilitando os logs do GC (pouco overhead e útil para troubleshooting em produção):
java -Xlog:gc*:file=/var/log/app-gc.log -jar app.jar
Você pode importar o arquivo de log app-gc.log
gerado em ferramentas de analise como GCEasy para entender exatamente o comportamento do GC, uso da memória heap e metaspace, possíveis vazamentos de memória e muitos mais.
Gerando heap dump em caso de OutOfMemoryError
:
java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./var/dumps/heapdump-app.hprof -jar app.jar
Ao ocorrer um OutOfMemoryError
a JVM vai gerar um arquivo com o snapshot da heap no momento do erro. O arquivo heapdump-app.hprof
será criado no diretório /var/dumps
. A ideia é importar este arquivo em alguma ferramenta ou serviço de analise de heap dump como VisualVM ou Eclipse MAT.
Gerando GC Logs durante toda a atividade da JVM (o overhead é minimo e deveria ser habilitado em produção):
java -Xlog:gc*:file=./var/gc/app-logs.gc -jar app.jar
A JVM vai gerar um ou mais arquivos com os logs do GC (métricas, eventos de coleta, tipos de coleta, tempo de cada coleta etc). O arquivo app-logs.gc
será criado no diretório /var/gc
. A ideia é importar este arquivo em alguma ferramenta ou serviço de analise de GC Logs, como GC Viewer ou GCEasy.
Terminando a aplicação em caso de OutOfMemoryError
:
java -XX:+ExitOnOutOfMemoryError -jar app.jar
Terminando a aplicação com mensagem de erro de crash em caso de OutOfMemoryError
:
java -XX:+CrashOnOutOfMemoryError -jar app.jar
Aqui seria um exemplo de erro gerado na saída padrão:
Aborting due to java.lang.OutOfMemoryError: GC overhead limit exceeded
# A fatal error has been detected by the Java Runtime Environment:
#
# Internal Error (debug.cpp:308), pid=26064, tid=0x0000000000004f4c
# fatal error: OutOfMemory encountered: GC overhead limit exceeded
#
# JRE version: Java(TM) SE Runtime Environment (8.0_181-b13) (build 1.8.0_181-b13)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.181-b13 mixed mode windows-amd64 compressed oops)
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# C:\workspace\rafael.ponte\trunk\buggyapp\hs_err_pid26064.log
#
# If you would like to submit a bug report, please visit:
# http://bugreport.java.com/bugreport/crash.jsp
#
Da mensagem acima, você pode observar o arquivo de log hs_err_pid26064.log
gerado no caminho C:\workspace\rafael.ponte\trunk\buggyapp\hs_err_pid26064.log
. Esse arquivo de core dump possui informações sobre o crash. Você pode usar ferramentas para analisar o log, como FastThread e VisualVM, mas a maior parte das informações presentes no arquivo de logs são bem básicas e talvez não suficientes para fazer troubleshooting de OutOfMemoryError
.
Podemos também exibir as informações de memória, CPU, system properties e locale usados pela JVM, o que é interessante para verificarmos se estamos definindo corretamente os parâmetros passados para aplicação. Por exemplo, para exibir as configurações de memória da VM basta executar:
java -XshowSettings:vm -version
E como resultado teremos (na minha máquina):
VM settings:
Max. Heap Size (Estimated): 3.08G
Using VM: OpenJDK 64-Bit Server VM
openjdk version "11.0.11" 2021-04-20
OpenJDK Runtime Environment (build 11.0.11+9-Ubuntu-0ubuntu2.20.04)
OpenJDK 64-Bit Server VM (build 11.0.11+9-Ubuntu-0ubuntu2.20.04, mixed mode)
Outras categorias podem ser informadas:
java -XshowSettings:vm -version # VM settings:
java -XshowSettings:system -version # Operating System Metrics
java -XshowSettings:properties -version # Property settings
java -XshowSettings:locale -version # Locale settings
java -XshowSettings:all -version # All settings