Recebi um erro "heap out of memory" na minha aplicação Java que está armazenado no Amazon Elastic Container Service (Amazon ECS). Para solucionar o erro, quero criar um arquivo .hprof e salvá-lo em um bucket do Amazon Simple Storage Service (Amazon S3).
Breve descrição
O motivo mais comum pelo qual você recebe uma exceção OutOfMemoryError é porque uma Java Virtual Machine (JVM) não consegue alocar memória suficiente para um heap. Quando uma aplicação Java é executado em um contêiner do ECS, um erro "heap out of memory" interrompe a aplicação e interrompe as tarefas do ECS. Todos os arquivos.hprof que a aplicação salva não estão mais disponíveis. Para solucionar o erro de exceção e depurar problemas de alocação de memória, você deve criar um arquivo .hprof e salvá-lo em um bucket do S3.
Resolução
Observação: A resolução a seguir resolve a maioria dos cenários de exceção de OutOfMemoryError. Para obter mais informações sobre a causa dos erros de memória Java, consulte Understand the OutOfMemoryError exception (Compreender a exceção OutOfMemoryError) no site da Oracle.
Crie um bucket do S3
Use o console do Amazon S3 para criar um bucket do S3 para armazenar seu arquivo.hprof.
Crie uma definição de tarefa do ECS
Use o console do Amazon ECS para criar uma definição de tarefa como um esquema para sua aplicação Java.
Para a variável de ambiente, forneça o nome do seu bucket do S3. Os comandos de inicialização da aplicação também usam o nome do bucket do S3.
Observação: HEAP_DUMP_BUCKET é a variável de ambiente nos comandos de exemplo.
Crie um perfil do IAM de tarefa do ECS
Crie um perfil do AWS Identity and Access Management (AWS IAM) para tarefas do ECS que inclua permissões s3:PutObject para que você possa fazer upload de arquivos.
Execute os comandos de inicialização
No diretório de trabalho da JVM, um despejo de heap padrão é criado em um arquivo chamado java_pidpid.hprof. Para especificar outro nome de arquivo ou diretório, use a opção XX:HeapDumpPath=.
O despejo de heap é gerado no diretório /tmp/heap_dump.hprof nos seguintes exemplos de comandos de inicialização:
CMD ["java", \
"-XX:+HeapDumpOnOutOfMemoryError", \
"-XX:HeapDumpPath=/tmp/heap_dump.hprof", \
"-XX:OnOutOfMemoryError=yum install -y aws-cli > /dev/null && aws s3 mv /tmp/heap_dump.hprof s3://$HEAP_DUMP_BUCKET/'date+%F_%T'.hprof ; kill -9 %p", \
"MemoryApp" \]
Exemplo de fluxo do comando de inicialização
Observação: se você receber erros ao executar comandos da AWS Command Line Interface (AWS CLI), consulte Solucionar erros da AWS CLI. Além disso, verifique se você está usando a versão mais recente da AWS CLI.
A opção OnOutOfMemoryError especifica um comando ou script a ser executado quando você recebe uma exceção OutOfMemoryError. Para obter mais informações sobre a opção OnOutOfMemoryError, consulte Java HotSpot VM command-line options (opções de linha de comando do Java HotSpot VM) no site da Oracle.
Conclua as etapas a seguir para o fluxo do comando OnOutOfMemoryError:
- Instale a AWS Command Line Interface (AWS CLI) em -y sem nenhuma interação. A saída do comando é salva em um arquivo temporário em /dev/null para que informações desnecessárias sobre a instalação da AWS CLI não sejam adicionadas aos logs de contêiner.
- Faça upload do arquivo .hprof para o bucket do S3 com permissões do perfil de tarefa do ECS. O arquivo .hprof é renomeado para seguir o padrão date+%F_%T.hprof.
- Analise os dados de log do Amazon CloudWatch:
2023-05-02T17:02:37.748+01:00 Hello, world! Hello Java! Good bye memory...
2023-05-02T17:02:37.748+01:00 Going to sleep for 2 ms...
2023-05-02T17:02:39.748+01:00 Wake now, lets heap the memory...
2023-05-02T17:02:39.748+01:00 java.lang.OutOfMemoryError: Requested array size exceeds VM limit
2023-05-02T17:02:39.748+01:00 Dumping heap to /tmp/heap_dump.hprof ...
2023-05-02T17:02:39.756+01:00 Heap dump file created [2893599 bytes in 0.008 secs]
2023-05-02T17:02:39.756+01:00 #
2023-05-02T17:02:39.757+01:00 # java.lang.OutOfMemoryError: Requested array size exceeds VM limit
2023-05-02T17:02:39.757+01:00 # -XX:OnOutOfMemoryError="yum install -y aws-cli > /dev/null && aws s3 mv /tmp/heap_dump.hprof s3://$HEAP_DUMP_BUCKET/`date +%F_%T`.hprof ; kill -9 %p"
2023-05-02T17:02:39.757+01:00 # Executing /bin/sh -c "yum install -y aws-cli > /dev/null && aws s3 mv /tmp/heap_dump.hprof s3://$HEAP_DUMP_BUCKET/`date +%F_%T`.hprof "...
2023-05-02T17:02:54.663+01:00 Completed 256.0 KiB/2.8 MiB (2.2 MiB/s) with 1 file(s) remaining
Completed 512.0 KiB/2.8 MiB (4.4 MiB/s) with 1 file(s) remaining
Completed 768.0 KiB/2.8 MiB (6.6 MiB/s) with 1 file(s) remaining
Completed 1.0 MiB/2.8 MiB (8.7 MiB/s) with 1 file(s) remaining
Completed 1.2 MiB/2.8 MiB (10.8 MiB/s) with 1 file(s) remaining
Completed 1.5 MiB/2.8 MiB (12.9 MiB/s) with 1 file(s) remaining
Completed 1.8 MiB/2.8 MiB (15.0 MiB/s) with 1 file(s) remaining
Completed 2.0 MiB/2.8 MiB (17.0 MiB/s) with 1 file(s) remaining
Completed 2.2 MiB/2.8 MiB (19.1 MiB/s) with 1 file(s) remaining
Completed 2.5 MiB/2.8 MiB (21.1 MiB/s) with 1 file(s) remaining
Completed 2.8 MiB/2.8 MiB (23.1 MiB/s) with 1 file(s) remaining
Completed 2.8 MiB/2.8 MiB (13.0 MiB/s) with 1 file(s) remaining move: ../tmp/heap_dump.hprof to s3://fargate-test-cluster-logs/2023-05-02_16:02:53.hprof
2023-05-02T17:02:54.705+01:00 Executing /bin/sh -c "kill -9 1"...
2023-05-02T17:02:54.707+01:00 Exception in thread "main" java.lang.OutOfMemoryError: Requested array size exceeds VM limit
2023-05-02T17:02:54.707+01:00 at MemoryApp.main(MemoryApp.java:13)
O exemplo anterior de dados de log usa yum install para a AWS CLI em um contêiner que executa a imagem do Amazon Corretto 17. Se a imagem do contêiner for baseada em um sistema operacional (SO) diferente, o comando será alterado. Veja a seguir exemplos de comandos para sistemas operacionais diferentes:
- Fedora Linux: dnf install -y awscli
- Debian: apt-get install -y awscli
- Alpine Linux: apk add aws-cli
Observação: Com qualquer sistema operacional, você deve usar um comando equivalente ao exemplo do comando yum install que instala a AWS CLI.