JVM 밑바닥까지 파헤치기 - 최적화 사례 분석 및 실전

유승선 ·2025년 2월 20일
0

자바 독학

목록 보기
12/16
post-thumbnail

이번 챕터는 JVM 튜닝의 실제 사례를 분석하고 알아보는 시간이다. 비록 실제 GC 튜닝 경험은 없지만 사례를 생각하면서 어떻게 하면 우리 서비스에 적용시킬 수 있을까에 대한 고민을 해본다.


사례

대용량 메모리 기기 대상 배포 전략

  • 상황 : 하루 페이지 뷰가 15만의 웹 사이트. 모든 하드웨어 자원을 온전히 혼자 사용하고 있기 때문에 여유로운 상황. 관리자는 -Xms 와 -Xmx 매게 변수를 지정하여 자바 힙 크기를 12GB 로 고정. 하지만 서버 실행 효율이 기대에 한참 못 미치고, 장시간 응답하지 않는 일이 발생했다.

  • 원인 : 원인은 GC에 있었다. 핫스팟 가상 머신을 서버 모드로 실행했고, Parallel GC 를 사용 중이다. 하지만 12GB 에 달하는 힙 메모리를 FULL gc 하기 위해서 최장 14초까지 정지가 된 상황이다. 서비스 특성 상, 사용자가 웹 페이지를 요청하면 해당 파일을 디스크 -> 메모리로 올리는데 이때 직렬화 하는 과정에서 메모리에 거대 객체가 쌓였다. 거대 객체는 구세대에 만들어졌고, 힙을 12GB 로 준비했지만 금방 차게 되어서 FULL gc 가 발생했고 10초씩 일시 정지되는 사태가 발생했다.

  • 분석 : 소스 코드 상관 없이 힙 메모리를 너무 크게 잡아서 회수하고 재활용하는데 오랜 시간이 걸린 것이다. 간단히 힙 크기를 1.5GB 나 2GB 로 줄여도 일시 정지 시간은 줄일 수 있다. 하지만 하드웨어 값을 낭비한 셈이 된다.

  • 해결 : JVM 의 모든 GC 는 특정한 애플리케이션 타입과 동작 시나리오를 목표로 설계되었다. 그렇기 때문에 애플리케이션을 이 시나리오에 알맞게 설정하는 것이 중요하다. 현재 시나이오의 문제를 해결한 방식은 32비트 가상 머신 다섯 개로 논리 클러스터를 구축하는 방식으로 해결 되었다. 메모리를 프로세스당 2GB씩 할당해서 (힙 크기는 1.5GB로 고정) 총 10GB를 활용하게 했다. 그리고 아파치 서비스를 두어 웹 사이트로 들어오는 부하를 분산하는 역할을 맡겼다. 추가적으로, 고객들은 응답 속도를 더 중요하게 생각함으로 CMS GC 로 변경해서 서비스가 장시간 정지하는 문제가 사라졌다.

내 생각 : 서비스를 분할해서 하드웨어 자원을 나누는것도 좋은 접근이 될 수 있다. 왜냐면 한 서버에서 너무 큰 GC 가 발생하게 되면 단일 장애 포인트가 생길 수 있고 이 사례처럼 지연시간이 길어질 수 있다. 하지만 멀티 스레드와 같이 멀티 프로세스로 나뉘게 되면 역시 동시성과 같은 문제 등은 여전히 생각해야 하는 과제일거 같다.

실전 : 이클립스 구동 시간 줄이기

클래스 로딩 시간 최적화

JVM 에서 클래스 로딩을 하는 시간은 생각보다 오래 걸린다. 로딩 과정에서 안전한 바이트코드인지 검증하는 단계를 거치기 때문에 이렇게 오랜 시간이 걸릴 수 있다. 하지만 이클립스와 같은 환경에서 JVM 어플리케이션을 실행 시킬 때는 이런 바이트코드 검증이 따로 필요 없음으로 가상 머신에 -Xverify:none 옵션을 설정하여 바이트 코드 검증을 건너뛰어서 클래스 로딩 속도를 개선시키는 방법도 있다.

컴파일 시간 최적화

JVM 에 컴파일 과정에서 핵심 적인 부분은 JIT 컴파일러라고 할 수 있다. 간단하게 말해, 컴파일 시간이 많이 소요되는 코드 (핫 코드) 를 가상 머신의 JIT 컴파일러에 캐싱하는 것이다, 그리고 이것을 컴파일 시간이라 볼 수 있다.

자바는 C 나 C++ 과는 다르게 바이트코드로 변환 된 .class 파일을 해석하여 실행하는 구조다. 그리고 이 속도는 상당히 느리다는 단점이 있다. JDK 1.2 이후에 JIT 컴파일러를 제공하기 시작하며, 일정 횟수 이상 호출 되는 자바 메서드를 핫 코드로 분류하여 JIT 컴파일러에 넘긴다. 그리고 자바 프로그램의 코드 자체에 문제가 없는 한 프로그램을 오래 실행할 수록 코드가 꾸준히 최적화 되어서 점점 빨라질 수 있다.

JVM 은 JIT 컴파일러를 억제하는 -Xint 매개 변수도 제공해준다. 즉, 가상 머신을 순수한 인터프리트 방식으로 수행할 수 있게 도와주지만 총 구동 시간으로 보면은 더 오래 걸릴 것이다.

profile
성장하는 사람

0개의 댓글