가장 중요한 JVM 파라미터들을 알아보자

Jake Seo·2021년 1월 28일
1

자바 잡지식

목록 보기
1/17

출처

https://www.baeldung.com/jvm-parameters

개요

자바를 실행할 때는 JVM(Java Virtual Machine)이라는 가상머신을 이용하게 된다. 이 JVM을 이용하다가 여러가지 문제에 부딪힐 때가 많은데 이를테면 메모리 문제라든지 테스트 환경에서 콘솔을 못 쓰는 문제라든지 가비지 컬렉션과 관련된 문제라든지 여러가지가 있다.

명시적 힙 메모리 - Xms과 Xmx 옵션

성능에 관련된 문제 중에 가장 흔한 문제는 애플리케이션이 요구하는 만큼 힙 메모리 초기화를 못할 때 일어나는 문제이다. 힙 사이즈의 최소 값과 최대 값을 줌으로써 이 문제를 해결할 수 있다. 아래는 힙 사이즈를 주는 방법이다.

-Xms<heap size>[unit]
-Xmx<heap size>[unit]

여기서 unit이란 것은 힙사이즈에 의해 표기되는 메모리에 초기화될 unit을 나타낸다. unit은 GB일 경우 'G', MB일 경우 'M', KB일 경우 'K' 로 표기될 수 있다.

이를테면 최소 2GB 메모리에서 최대 5GB 메모리까지 JVM에 할당하고 싶다면, 다음과 같이 작성하면 된다.

-Xms2G -Xmx5G

자바8부터, Metaspace의 사이즈는 정의되지 않았다. 전역 리미트에 걸리게 되면, JVM은 자동으로 이 사이즈를 늘려나간다. 하지만, 불필요한 불안정성을 극복하기 위해서, 다음과 같이 Metaspace를 조정할 수 있다.

-XX:MaxMetaspaceSize=<metaspace size>[unit]

metaspace에 대해서는 여기 링크에 잘 나와있다.

metaspace size라는 것은 말 그대로 metaspace에 들어갈 메모리의 양을 표기하는 것이다. 오라클의 가이드라인에 따르면, 총 사용 가능한 메모리 다음에, 가장 영향력 있는 요소는 Young Generation에 대한 힙의 양이다. 기본 값으로는 1310MB가 들어가있고, 최대 값으로는 제한이 없다.

힙은 Young GenerationTenured Generation으로 나누어져있다고 한다. 참고 링크

다음과 같이 할당해줄 수 있다.

-XX:NewSize=<young size>[unit]
-XX:MaxNewSize=<young size>[unit]

가비지 콜렉션

안정적인 앱을 위해서 올바른 가비지 콜렉션 알고리즘은 필수적이다. JVM은 4가지 종류의 가비지 콜렉션 구현이 있다.

  • Serial Garbage Collector
  • Parallel Garbage Collector
  • CMS Garbage Collector
  • G1 Garbage Collector

아래와 같은 파라미터를 이용함으로써 구현이 선언될 수 있다.

-XX:+UseSerialGC
-XX:+UseParallelGC
-XX:+UseParNewGC
-XX:+USEG1GC

각 가비지 콜렉션에 대한 자세한 내용은 여기에서 살펴볼 수 있다.

가비지 콜렉션 로깅

어플리케이션 상태에 대한 엄격한 모니터링을 위해, JVM 가비지 콜렉션 성능을 항상 체크해야 한다. 가장 쉬운 방법은 가비지 콜렉션 활동 로그를 사람이 읽기 쉬운 형태로 표기해주는 것이다. 아래의 파라미터를 통해서 가비지 콜렉션 활동 로그를 남길 수 있다.

-XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=< number of log files >
-XX:GCLogFileSize=< file size >[ unit ]
-Xloggc:/path/to/gc.log

UseGCLogFileRotation은 로그 파일 롤링 정책을 명시한다. log4j, s4lj 등과 같이 말이다. NumberOfGCLogFiles는 단일 어플리케이션 라이프사이클에서 로그파일이 최대 몇개까지 쓰여질 수 있는지를 나타낸다. GCLogFileSize는 로그 파일의 최대 크기를 명시한다. loggc는 로그 파일의 위치를 명시한다.

눈여겨볼 점은, 2개의 JVM 파라미터가 더 있다는 건데, (XX:+PrintGCTimeStamps-XX:PrintGCDateStamps) 가비지콜렉션 로깅에서 날짜 형식에 맞는 타임스탬프를 출력할 때 유용하다.

이를테면, 최대 100개의 가비지 콜렉션 로그 파일을 할당하고 싶고, 각 파일은 50MB 사이즈를 최대 크기로 가지며, '/home/user/log/' 위치에 저장하고 싶다면, 아래와 같은 설정을 해줄 수 있다.

-XX:+UseGCLogFileRotation
-XX:NumberOfGCLogFiles=10
-XX:GCLogFileSize=50M
-Xloggc:/home/user/log/gc.log

하지만, 문제는 하나의 추가적인 데몬 스레드가 항상 모니터링 시스템을 위해 백그라운드에 돌아가고 있다는 것이다. 이 행위가 오히려 퍼포먼스 보틀넥을 만들 수도 있다; 그래서 프로덕션 레벨에서는 파라미터 가지고 잘 놀지 않는다.

OOM 핸들링하기

규모가 큰 앱에서는 out of memory error를 만나기 쉽다. 일명 OOM(Out Of Memory)에러는 결국 앱을 중단시킨다. 이러한 에러는 매우 크리티컬하며, 문제를 재현해서 트러블슈팅하기 매우 어렵다.

JVM에서는 아래와 같은 파라미터를 제공하여, 힙 메모리를 물리적인 파일로 덤프할 수 있다. 이 파일은 나중에 메모리 유출을 찾는데 기여할 수 있다.

-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=./java_pid<pid>.hprof
-XX:OnOutOfMemoryError="< cmd args >;< cmd args >"
-XX:+UseGCOverheadLimit
  • HeapDumpOnOutOfMemoryError 는 JVM에게 OutOfMemory 에러가 났을 때 물리적인 파일로 힙을 덤프하라는 뜻이다.
  • HeapDumpPath는 파일이 쓰일 곳의 경로를 말한다. 어떤 파일 이름도 주어질 수 있다. 하지만, 만일 JVM이 <pid> 태그를 이름에서 찾는다면, OutOfMemory 에러를 일으킨 현재 프로세스의 프로세스 id가 .hprof 포맷과 함께 파일 이름에 추가될 것이다.
  • OnOutOfMemoryErrorOutOfMemory 에러가 발생했을 때, 실행될 긴급 명령어를 적어놓을 수 있다. 적절한 명령어를 "< cmd args>" 자리에 넣으면 된다. 이를테면, 만일 OutOfMemory 직후에 서버를 재시작하고 싶다면, 다음과 같이 설정하면 된다.
-XX:OnOutOfMemoryError="shutdown -r"
  • UseGCOverheadLimitOutOfMemory 에러가 던져지기 이전에 GC에서 소비되는 가상머신의 시간의 영역을 제한하는 정책이다.

32/64 비트

OS 환경에서는 32비트와 64비트 패키지가 설치된다. JVM은 자동으로 32비트 환경 패키지를 선택한다.

수동으로 64비트를 선택하고 싶다면, 아래와 같은 파라미터를 이용하면 된다.

-d<OS bit>

<OS bit>32 또는 64가 될 수 있다. 더 많은 정보는 여기에서 확인해볼 수 있다.

잡다한 정보

  • -server: "Server Hotspot VM"을 활성화한다. 이 파라미터는 64비트 JVM에서 기본값으로 사용된다.
  • -XX:+UseStringDuplication: 자바 8u20에서 이 JVM 파라미터를 도입했다. 같은 문자열의 너무 많은 인스턴스를 만듦으로써 불필요한 메모리를 사용하는 것을 줄인다. 이 파라미터는 중복된 문자열 값들을 하나의 글로벌 char[] 배열로 복사함으로써 힙메모리를 최적화한다.
  • -XX:+UseLWPSynchronization: LWP(Light Weight Process) 를 설정한다. 쓰레드를 기반으로 하지 않고, Light Weight 프로세스 동기화 정책을 기반으로 한다.
  • -XX:LargePageSizeInBytes: 자바 힙을 위해 사용되는 큰 페이지 사이즈를 설정한다; GB/MB/KB에서 인자를 받는다. 더 큰 페이지 사이즈를 설정함으로써, 가상 메모리 하드웨어 리소스의 사용을 더 좋게 만들 수 있다; 하지만, PermGen을 위한 더 큰 공간 사이즈를 일으킬 수 있다. 결과적으로 힙 공간의 사이즈를 강제로 줄일 수도 있다.
  • -XX:MaxHeapFreeRatio: shirinking 을 피하기 위해 가비지 컬렉션 이후에 최대 퍼센티지의 힙 여유 사이즈를 설정한다.
  • -XX:MinHeapFreeRatio: expansion 을 피하기 위해 가비지 컬렉션 이후에 최소 퍼센티지의 힙 여유 사이즈를 설정한다. 힙의 사용량을 모니터링하기 위해 JDK에서 제공하는 VisualVM을 사용할 수 있다.
  • -XX:SurvivorRatio: eden/survivor 영역 사이즈 의 비율이다. 이를테면, -XX:SurvivorRatio=6 이라는 설정을 한다면 survivor space와 eden space의 비율은 1:6이 될 것이다.
  • -XX:+UseLargePages: 시스템에 의해 지원된다면, 큰 페이지 메모리를 사용한다. OpenJDK7에서는 이 파라미터 때문에 앱이 박살나기도 하기 때문에 알아두어야 한다.
  • -XX:+UseStringCache: 일반적으로 할당되는 문자열들의 캐시를 String 풀에서 이용 가능하게 한다.
  • -XX:+UseCompressedString: String 오브젝트들에 대해 byte[] 타입을 사용한다. 이 결과로 문자열을 순수한 ASCII 포맷으로 표현이 가능하다.
  • -XX:+OptimizeStringConcat: 가능한 String을 합치는 것(concatenation 연산)을 최적화한다.

결론

일반적인 어플리케이션 퍼포먼스를 증대시키기 위해 사용될 수 있는 JVM 파라미터들에 대해 알아보았다. 몇몇가지는 디버깅 목적으로 사용될 수 있다.

여기에서 더 많은 파라미터들을 자세히 알아볼 수 있다.

profile
풀스택 웹개발자로 일하고 있는 Jake Seo입니다. 주로 Jake Seo라는 닉네임을 많이 씁니다. 프론트엔드: Javascript, React 백엔드: Spring Framework에 관심이 있습니다.

0개의 댓글