성능 지표
| EN | KR | e.g. |
|---|
| Throughput | 처리율 | 초당 처리된 트랜잭션 |
| Latency | 지연 | 평균 요청 처리 시간 |
| Capacity | 수용량 | 최대 동시 처리 가능 요청 수 |
| Utilization | 사용률 | 평균 CPU 사용률 |
| Efficiency | 효율 | throughput / 비용 |
| Scalability | 확장성 | 리소스 추가에 따른 throughput 향상 정도 |
| Degradation | 저하 | 부하 증가에 따른 throughput 감소 정도 |
GC
용어
- STW; Stop the world
GC를 위해 모든 애플리케이션 스레드를 정지하는 것
- Safepoint
GC를 위해 스레드가 중단될 수 있는 지점. 스레드 내 고정된 자료구조를 볼 수 있다. JVM이 강제로 스레드를 safepoint 상태로 바꿀 수는 없다. 대신 스레드가 safepoint 상태에서 벗어나지 못하게 할 수는 있다
힙 = Young Generation + Old Generation
- Young Generation
- Eden Space : 최초 생성된 객체들
- Survivor Space : Eden에서 수집 제외된 객체들
From, To 두 단계로 구분되며, 이후 Tenured로 이동
Young Generation이 큰 경우 덜 자주 수집되고, 더 적은 객체가 Old Generation으로 이동. 대신 Old Generation이 작아 풀 GC는 더 자주 일어난다
- Tenured(Old) : Survivor에서 수집 제외된 객체들
- Permanent Generation
GC 알고리즘 선정 시 유의사항
- 각 GC로 인한 중단 기간
- 처리율 : 전체 런타임 대비 GC 시간
- 중단 빈도
- 회수 효율
- 중단 일관성 : 중단 기간 일정한지
GC 종류
- 병렬 GC
되도록 STW를 줄이기 위해 병렬 스레드 이용. 가능한 경우 애플리케이션과 동시 실행
- Parallel GC
단순한 영 세대용 병렬 GC
- ParNew GC
CMS GC와 함께 사용할 목적으로 Parallel GC를 변형한 것
- ParallelOld GC
올드 세대용 병렬 GC. 객체를 재배치하여 메모리 단편화가 발생하지 않는다
- CMS; Concurrent Mark Sweep
↓bash
java ... -XX:+UseConcMarkSweepGC
# ParNew GC도 같이 작동한다
- 올드 영역 GC의 STW를 짧게 하기 위해 개발됨
- 메모리 압착을 하지 않아 단편화 발생 가능
- 올드 영역 메모리가 아예 부족해진 경우(CMF; Concurrent Mode Failure) ParallelOld GC 실행
- G1; Garbage First
↓bash
java ... -XX:+UseG1GC
# Java 9부터는 default GC
-XX:MaxGCPauseMillis=200
# 최대 중단 시간 목표치(ms). 즉 실제로는 넘을 수 있음
- 대용량 힙에서 짧은 STW로 작동하는 수집기
- 힙을 여러 영역(region)으로 나누고, 영/올드 세대를 불연속적으로 배치할 수 있다
- 메모리 압착 수행
JVM 파라미터
- Boolean flag
↓bash
XX:+FlagName
XX:-FlagName
- Value flag
↓bash
-XX:FlagName=value
주요 플래그
- 힙 크기 관련
↓bash
-XmsN # 초기값
-XmxN # 최대값
-XX:MaxPermSize=N # ~ Java 7
-XX:MaxMetaspaceSize=N # Java 8 ~
# 힙 덤프 관련
-XX:+HeapDumpOnOutOfMemoryError # 메모리 부족시 힙 덤프 생성
-XX:HeapDumpPath={path} # 힙 덤프 작성 위치
-XX:+HeapDumpBeforeFullGC # 풀 GC 전에 힙 덤프 생성
-XX:+HeapDumpAfterFullGC # 풀 GC 후에 힙 덤프 생성
# 아래 부분은 알아서 잘 설정되며, Parallel GC에서 최후의 수단으로 조정
-XX:NewSize=N # Young Generation 초기 크기
-XX:MaxNewSize=N # Young Generation 최대 크기
-XmnN # NewSize, MaxNewSize 동일하게 설정
-XX:NewRatio=N # (Young Generation 초기 크기) = (힙 초기 크기) / (1 + NewRatio)
-XX:SurvivorRatio=N # (Young Generation 크기) = N * (Survivor Space 크기)
# MaxGCPauseMillis를 제외한 G1 튜닝을 하려면 아래 옵션을 켜야 한다
-XX:+UnlockExperimentalVMOptions
힙 덤프 해석 툴 예 : heaphero
- GC 관련
↓bash
-XX:ParallelGCThreads=N # 병렬 스레드 개수
-XX:GCHeapFreeLimit=N # 풀 GC로 힙의 N% 이상 해제되면 OK
-XX:MaxTenuringThreshold=N # 테뉴어드 영역으로 승격되기 전까지 통과해야 하는 수집 횟수
# JDK 8 GC logging
-XX:+PrintGCDetails # GC 이벤트 로깅 ON
-XX:+PrintTenuringDistribution # 상세 정보 포함
-XX:+PrintGCTimeStamps # VM 이후 경과한 시간
-XX:+PrintGCDateStamps # 이벤트 시각(벽시계 기준)
-XX:+PrintGCApplicationStoppedTime
-Xloggc:/var/log/app/gc.log
-XX:+UseGCLogFileRotation
-XX:+NumberOfGCLogFiles=10
-XX:+GCLogFileSize=10m
# JDK 9+ GC logging
-Xlog:gc*,gc+age=trace,safepoint:file=/var/log/app/gc.log:utctime,pid,tags:filecount=10,filesize=10m
GC 로그는 GCViewer 등으로 시각화 가능
- JIT 관련
↓bash
-XX:ReservedCodeCacheSize=N # 최대 코드 캐시 크기. 최초 설정 후 동적으로 확장되지 않는다
-XX:+PrintCompilation # 어떤 메서드가 JIT 컴파일 됐는지 STDOUT 출력
- Default networking timeout
↓bash
-Dsun.net.client.defaultConnectTimeout=2000 # 2000ms
-Dsun.net.client.defaultReadTimeout=2000 # 2000ms
Java 옵션(JAVA_OPTS)
- user.timezone 프로퍼티 기본값 지정
↓shell
$ java -Duser.timezone=Asia/Seoul
- 인코딩 관련 설정
↓shell
$ java -Dfile.encoding=UTF-8 -Dfile.client.encoding=UTF-8 -Dclient.encoding.override=UTF-8
- 리모트 디버깅 설정
↓shell
# Before JDK 1.4
$ java -Xnoagent -Djava.compiler=NONE -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address="*:55555"
# For JDK 1.4
$ java -Xdebug -Xnoagent -Xrunjdwp:transport=dt_socket,address="*:55555",server=y,suspend=n
# address : 수신 허용 범위
# server : 서버로 작동할지 여부
# suspend : 디버거 부착까지 기다릴지 여부
# After JDK 1.4
$ java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address="*:55555"
jcmd Since Java 8
JDK 기본제공 분석 도구
- 자바 프로세스 목록
↓shell
$ jcmd
- 사용 가능 명령
↓shell
$ jcmd {pid} help
- 힙 히스토그램
↓shell
$ jcmd {pid} GC.class_histogram # GC 실행. 실행 후 힙 상태
$ jmap -histo {pid} # GC 실행 X. 현재 힙 상태
- 힙 덤프
↓shell
$ jcmd {pid} GC.heap_dump ./out.hprof
- 시스템 프로퍼티
↓shell
$ jcmd {pid} VM.system_properties
- 쓰레드 덤프
↓shell
$ jcmd {pid} Thread.print
jhsdb Since Java 9
JDK 기본제공 디버거; Java Hotspot Debuggerjhsdb
- JVM에 디버거 부착 시 실행이 일시중지됨에 유의
- 사용
↓shell
# clhsdb 커맨드라인 디버거
$ jhsdb clhsdb [--pid pid | --exe executable --core coredump]
# hsdb GUI 디버거
$ jhsdb hsdb [--pid pid | --exe executable --core coredump]
# debugd 리모트 디버그 서버 시작
$ jhsdb debugd [options] pid [server-id]|[option] executable core [server-id]
개요
커맨드라인 JDK 툴과 가벼운 프로파일 기능을 포함하는 자바 프로세스 시각화 툴
Remote 프로세스 연결
- Add Remote Host
호스트 주소 입력
- Add JMX Connection or Add jstatd Connection
↓JMX 활성화
-Dcom.sun.management.jmxremote.local.only=false \
-Dcom.sun.management.jmxremote.host=172.159.246.217 \ # ifconfig로 확인
-Dcom.sun.management.jmxremote.port=11099 \
-Dcom.sun.management.jmxremote.rmi.port=11099 \
-Dcom.sun.management.jmxremote.ssl=false \
-Dcom.sun.management.jmxremote.authenticate=false \
-Djava.rmi.server.hostname=172.159.246.217 \
마이크로 벤치마크 유의사항
- 메서드 테스트 전에, 여러번 호출하여 워밍업하는 것이 좋다
- 도중에 GC가 일어나지 않도록 하는 것이 좋다Epsilon Since Java 11
- 컴퓨터의 엔트로피를 이용하는 SecureRandom, SSL연결은 엔트로피를 사용할 수 있을 때까지 대기하므로 유의