서비스 중 JVM heap memory가 지속적으로 증가함에 따라 OOM이 발생했고, OOM 시 heap dump를 떠서 분석한 과정을 공유합니다.
결국 OOM이 발생했고, 사전에 OOM 발생 시 heap dump를 남기는 JVM Option 추가 작업 및 k8s preStop hook으로 해당 heap dump 파일을 s3 경로로 copy하는 작업을 해두었다
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${heapDumpPath}
lifecycle:
preStop:
exec:
command:
- /bin/sh
- '-c'
- >
POD_NAME=$(hostname)
CURRENT_DATE=$(date +%Y-%m-%d)
aws s3 cp /tmp/heapdumps/*.hprof
s3://bucket/$CURRENT_DATE/$POD_NAME/
sleep 10
@Slf4j
@Service
public class RedisMessageSubscriber implements MessageListener {
public static List<String> messageList = new ArrayList<>();
public void onMessage(final Message message, final byte[] pattern) {
messageList.add(message.toString());
log.debug("Message received: " + new String(message.getBody()));
}
}
해당 서비스는 Redis publish를 하고 subscribe 하는 부분은 없는데 테스트 목적으로 작업했던 코드가 문제를 일으켰다 (삭제했어야 하는 클래스이다 ! ! !)
다른 서비스에서 publish한 메시지를 위의 리스너가 subscribe하면서 messageList.add를 하고 있던게 OOM 문제의 원인이었다.
-> 해당 서비스와 연관없는 메시지를 list에 저장하고 있었다...
@Service로 등록된 객체는 Spring 컨테이너가 관리하므로, 컨테이너가 해당 객체를 참조하고 있는 동안에는 GC 대상이 되지 않는다.
static으로 선언된 변수나 객체는 GC의 대상이 아니다.