성능 측정 시, 공정하게 테스트를 해야한다.
➡️ 이것을 지키는 것은 매우 어렵다
JVM과 Java Runtime
- JVM은 자바 바이트코드를 실행하는 데 중점을 두는 가상 머신
- 자바 런타임은 JVM 뿐만 아니라 자바 애플리케이션을 실행하는 데 필요한 라이브러리와 기타 파일을 포함한 더 넓은 개념
➡️ 간단히 말해, JVM은 자바 런타임의 핵심 구성요소 중 하나이며, 자바 런타임은 JVM을 포함하여 자바 프로그램을 실행하는 데 필요한 모든 것을 제공한다
JVM은 개발자가 작성한 코드를 자동 최적화 한다.
최적화가 미치는 영향을 구체적으로 완전히 이해하고 설명하는 것은 어렵다
🤯 Java 코드는 JIT 컴파일러, 메모리 관리, 그밖의 Java Runtime이 제공하는 서브 시스템을 떼놓고 생각할 수 없다
🤯 테스트 실행시의 OS, HW, Runtime 조건의 작용또한 무시할 수 없다
벤치마크 중, JVM이 메서드 호출을 최적화할 수 있다
➡️ 성능 캡처 전 JVM이 가동 준비를 마칠 수 있게 warm up 기간을 준다
💁🏻♀️ 벤치마크 대상 코드를 여러번 반복 실행한다
💡 힙 크기 조정하는 법 법: -Xms, -Xmx option
java -Xms2048m -Xmx2048m -XX:+PrintCompilation [벤치마크 대상]
GC가 일어날 가능성이 큰 시기에 캡쳐하지 않는다
(하지만 GC 수집은 불확정적이어서 어쩔 도리가 없다...)
💡 GC Log 보는 법: -verbose:gc option
java -Xms2048m -Xmx2048m -verbose:gc [벤치마크 대상]
테스트하려는 코드에서 생성된 결과를 실제로 사용하지 않는다
public class ClassicSort {
private static final List<Integer> testData = new ArrayList<>();
public static void main(String[] args) {
// testData List 생성
double startTime = System.nanoTime();
for (int i = 0; i < I; i++) {
List<Integer> copy = new ArrayList<>(testData);
Collections.sort(copy)
}
double endTime = System.nanoTime();
// 벤치마킹 코드 실행시간 출력
}
}
위 코드에서 copy List를 만들고, sort했지만 그뒤에 sort를 가져다 쓰는 곳이 없기 때문에 JIT 컴파일러가 이것을 죽은 코드 경로로 식별하고 벤치마킹 대상을 최적화 할 수 있다
위에서 설명한 것 처럼 마이크로벤치마킹 시 신경써야 할 것이 많았다.
하지만 멀티스레드 코드라면? 더 어려워진다.
위에서 설명한 것 처럼, 마이크로벤치마킹은 어렵지만 해야만 하는 상황이 있다면 마이크로벤치마킹 툴의 업계 표준인 JMH(Java Microbenchmark Harness)를 사용하자!
JMH는 Java를 비롯해 JVM을 타깃으로 하는 언어로 작성된 나노/마이크로/밀리/매크로 벤치마크를 제작, 실행, 분석하는 Java 도구이다
벤치마크 프레임워크는 어떤걸 벤치마킹 할 지 알 수 없으므로 동적이어야 한다
➡️ 리플렉션 사용시, 벤치마크 실행 경로에 복잡한 JVM 서브시스템이 끼어들게 된다
➡️ JMH는 벤치마크 코드에 annotation을 붙여 Java 소스를 추가 생성한다
https://github.com/openjdk/jmh
모든 측정은 어느 정도의 오차를 수반한다

(출처: https://www.dailyvet.co.kr/news/practice/companion-animal/88473)
"웹 애플리케이션 응답" 그래프이다

빨간색 구간의 경우, 404 Error(Client Error)일 것이다
➡️ 매핑되지 않은 URL 요청 시, 곧장 404를 반환하기 때문이다
파란색 구간의 경우, 서버 Error일 것이다(장시간 부하 및 타임아웃)
노란색 구간의 경우, 성공한 요청일 것이다
유의미한 하위 구성요소들로 분해하는 개념은 유용하다