강제 GC 명령과 Heapdump, shutdownHook

kwak woojong·2023년 8월 29일
0

Java로 프로세스를 만들고 1달 내내 잘 굴리다가 (안껐음)

GC가 계속 돌면서 Stop The WORLD가 된 상황에 이게 머선 일인가 싶어서

Heapmemory를 들쎠봤다.

jmap -dump:format=b,file=<filename>-0.hprof <PID>

상기 커맨드로 heapdump를 뜨고 Intellij에 드래그 드랍하면 JVM 메모리가 다뜬다.

GC가 돌면서 뭔가를 못지우고 있으니까 메모리가 100%를 점유하고 그래서 프로세스가 멈춘다고 생각함.

GracefulShutdown을 위해 ShutdownHook을 걸어놨는데, Runtime에서 이 ShutdownHook 쓰레드를 물고 있으니, 생성된 객체가 사라지지 않고 메모리에 계속 남는 상황이었음.

이게 TCP 서버였고, 다른 소켓이 붙을 때 핸들러를 생성하는데, 이 녀석 버퍼에 뭔가가 남아 있는 상태에서 시스템 다운 시그널을 받을 경우 Graceful 다운 시키려고 만든 셧다운 스레드 였는데, 소켓이 해제 됐다가 다시 연결되고 이를 반복하게 될 경우 시스템 다운 시그널도 안받았고, 핸들러의 shutdown 스레드를 Runtime에서 잡고 있으니, 이게 GC가 안쓸고 가는 거였음.

Runtime.getRuntime().addShutdownHook(hook);

소켓 해제 될 때를 close() 메서드를 호출하는 부분이 있는데, 여기에

Runtime.getRuntime().removeShutdownHook(hook);

이런 식으로 Hook을 없애주면 GC가 돌면서 메모리를 잘 없애준다.

문제는 모든 소켓 해지시 저 removeShutdownHook을 호출해줘야 하는데, 설계가 잘못 돼 있다면 여전히 메모리 누수가 발생할거다. 조심히 사용 할 것

암튼 removeShutdownHook을 사용한 후에 강제로 GC를 돌려봄

jcmd <pid> GC.run

상기 커맨드를 사용하면 강제로 GC를 돌린다. 덤프를 다시 뜨든 sysout을 찍든 해서 생성된 객체가 잘 사라졌는지 확인해보자.

profile
https://crazyleader.notion.site/Crazykwak-36c7ffc9d32e4e83b325da26ed8d1728?pvs=4<-- 포트폴리오

0개의 댓글