generated from Learning-Is-Vital-In-Development/study-template
-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
129 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
# 5장 마이크로벤치마킹과 통계 | ||
|
||
**목표** : 테스트 진행 시 **Warm Up**을 진행하라는데, 실제 얼마나 영향을 미치는지 확인해보기! | ||
|
||
### 벤치마킹 시 주의해야 하는 JVM Warm up | ||
|
||
|
||
💡 **JVM Warm up이란?** | ||
|
||
JVM은 코드를 1차적으로 바이트코드로 변환한 뒤, 기계어로 컴파일하는 2차 과정을 한번 더 거친다. | ||
이때 기계어 컴파일을 실행하는게 **JIT Compiler**이다. | ||
|
||
JIT Compiler는 총 5단계의 레벨을 가진다. 단계에 따라 내부적으로 동작하는 방식이 달라짐. | ||
Level 0~3 까지는 **C1 Compiler**가 담당, Level4는 **C2 Compiler**가 담당 | ||
|
||
**코드의 복잡도**, **실행 빈도**에 따라 코드의 레벨이 결정된다. Level4의 코드는 C2 Compiler를 사용해서 **코드 캐시 영역에 캐싱**한다. | ||
|
||
|
||
|
||
**JIT Compiler 구조** | ||
|
||
<img width="500" alt="스크린샷 2024-01-10 오후 2 00 54" src="https://github.com/CMC11th-Melly/Melly_Server/assets/82302520/84c1df22-196d-47e1-86f0-da5ce436628d"> | ||
|
||
**자바 최적화 136 페이지 코드** | ||
|
||
```java | ||
public class MyBenchmark{ | ||
|
||
public static void main(String[] args) throws RunnerException{ | ||
|
||
Options opt = new OptionBuilder() | ||
.include(SortBenchmark.class.getSimpleName()) | ||
.warmupIterations(100) | ||
.measurementIterations(5).forks(1) | ||
.jvmArgs("-server", "-Xms2048m", "-Xmx2048m").build(); // 해당 부분 | ||
|
||
new Runner(opt).run(); | ||
} | ||
} | ||
``` | ||
|
||
책 **136p**의 main() 메서드 코드를 보면 jvmArgs의 인자로 `-server`를 주는걸 알 수 있다. java8 이전까지는 이 옵션을 줘야 C2 Compiler를 사용할 수 있었다. java8 이후로는 기본적으로 C2 Compiler를 사용하도록 설정되어 있음. **** | ||
|
||
코드 캐시 사용 여부에 따라서 얼마나 성능 차이가 나는지 직접 스프링을 띄워서 확인해보자. | ||
|
||
```java | ||
@Service | ||
@RequiredArgsConstructor | ||
public class TestService { | ||
|
||
public void test(){ | ||
|
||
List<Integer> testData = new ArrayList<>(); | ||
Random randomGenerator = new Random(); | ||
|
||
for(int i =0; i < 1_000; i++){ | ||
testData.add(randomGenerator.nextInt(Integer.MAX_VALUE)); | ||
} | ||
|
||
/* | ||
C2 컴파일러로 캐싱되려면 실행 빈도가 높아야하고, 극단적인 상황에서의 성능 차이를 보기 위해서 | ||
여러번 정렬하는 코드를 수행 | ||
*/ | ||
for(int i =0; i < 10_000; i++){ | ||
testData.stream().filter(test -> test % 2 == 0).sorted().toList(); | ||
} | ||
} | ||
} | ||
``` | ||
|
||
- **Pinpoint**를 사용해서 메서드 실행 시간 측정 | ||
- jvmArgs로 `-XX:TieredStopAtLevel=N`을 설정하면 어느 레벨까지 사용할지 지정 가능하다 | ||
|
||
### -XX:TieredStopAtLevel=3 (컴파일 최적화는 하지만 코드 캐싱 안함) 테스트 | ||
|
||
--- | ||
|
||
**전체 응답 시간** | ||
|
||
<img width="700" alt="스크린샷 2024-01-10 오후 2 00 54" src="https://github.com/CMC11th-Melly/Melly_Server/assets/82302520/f245028a-833d-4878-94f2-387d1a232aa3"> | ||
|
||
|
||
**메서드 실행 시간** | ||
|
||
<img width="700" alt="스크린샷 2024-01-10 오후 2 00 54" src="https://github.com/CMC11th-Melly/Melly_Server/assets/82302520/45a0d245-187f-4e39-bafd-e16eb5c6b79b"> | ||
|
||
- 💡 코드 캐시를 미사용하는 경우 약 **1000ms**의 소요시간이 걸림. Level 3는 최적화된 컴파일을 하는 단계이기 때문에 더이상 시간 감축 불가능함. | ||
|
||
|
||
### -XX:TieredStopAtLevel=4 (default) 테스트 | ||
|
||
--- | ||
|
||
**전체 응답 시간** | ||
<img width="700" alt="스크린샷 2024-01-10 오후 2 00 54" src="https://github.com/CMC11th-Melly/Melly_Server/assets/82302520/a0ad2b9f-d524-4b22-a0df-c9cc768e2136"> | ||
|
||
|
||
**메서드 실행 시간** | ||
<img width="700" alt="스크린샷 2024-01-10 오후 2 00 54" src="https://github.com/CMC11th-Melly/Melly_Server/assets/82302520/cd654f31-aee6-4942-8a97-d6fe7c70a9fa"> | ||
|
||
|
||
|
||
- 💡 코드 캐시를 사용하는 경우 약 **270ms**의 소요시간이 걸림. 코드 캐시 미사용시보다 약 **5배** 성능 개선 | ||
|
||
|
||
### C1 Compiler & C2 Compiler 장단점 | ||
|
||
--- | ||
|
||
C1 Compiler (TieredStopAtLevel=1 설정 시) | ||
|
||
- 컴파일 시 최적화를 하지 않기 때문에 부팅 속도가 빠르다. | ||
- 보통 모바일 클라이언트에서 사용. **빠르게 부팅되는게 중요하다** | ||
- Intellij도 자세히 보면 어플리케이션 실행할때 TieredStopAtLevel=1로 동작. 설정에서 비활성화 가능 | ||
- 최적화 많이 하지 않기 때문에 **CPU 사용량 낮음** | ||
|
||
C2 Compiler (default 옵션) | ||
|
||
- 코드 캐시나 컴파일 최적화를 모두 진행하기 때문에 오래 동작하는 서버 어플리케이션에 적합 | ||
- 최적화를 많이 하기 때문에 **CPU 사용률 다소 높음** | ||
|
||
### (추가) 스프링 첫 로딩 시 지연시간 | ||
|
||
--- | ||
<img width="700" alt="스크린샷 2024-01-10 오후 2 00 54" src="https://github.com/CMC11th-Melly/Melly_Server/assets/82302520/5c54e3ca-7885-49f4-b02c-c6edcdb88eea"> | ||
|
||
스프링 처음 띄운 후에 요청 보내보면 엄청 지연되는걸 경험했을 것이다. | ||
|
||
스프링은 빠른 로딩을 위해서 어플리케이션이 부팅될때는 디스패처 서블릿을 초기화 하지는 않고, **첫 요청이 들어오면 초기화**를 하기 때문에 첫 요청의 응답속도가 느리다. |