공공부하자개발 · 영어 학습 노트
자바
실무 확장Excel · 파일 업로드 · DB 연동0/22 완료
  • 01Excel(XLSX) 구조와 순수 JDK로 읽기/쓰기
  • 02Apache POI로 Excel 업로드/다운로드
  • 03파일 업로드/다운로드 서버 (HttpServer)
  • 04JDBC 기초와 트랜잭션 (H2)
  • 05MyBatis 어노테이션 매퍼로 쿼리 연동
  • 06MyBatis XML 매퍼 · Oracle 방언 · PageHelper · Spring Boot
  • 07REST API 서버와 JSON
  • 08Vue 3 SPA 와 Java 서버 연동
  • 09@Scheduled 운영
  • 10로깅 실무: 레벨·계층, MDC 추적, 예외·성능, 마스킹, 롤링, JSON 로그
  • 11외부 API 연동
  • 12테스트 실무
  • 13암호화·개인정보 보호
  • 14인코딩·한글 실무
  • 15@Transactional 심화
  • 16긴 작업 비동기 처리와 진행률
  • 17SFTP·FTP 파일 연계
  • 18로컬 캐시와 @Cacheable
  • 19메일·알림 발송
  • 20웹 보안 체크리스트
  • 21빌드 도구와 폐쇄망 의존성 반입
  • 22성능 측정: p50·p95·p99, 측정 계층, JFR, JMH 함정, 자체 부하 테스트, 병목 순위
사이트 소개개인정보처리방침연락처
© 2026 공부하자
홈 › 실무 확장 › 22 / 22

성능 측정: p50·p95·p99, 측정 계층, JFR, JMH 함정, 자체 부하 테스트, 병목 순위

섹션 7진행 0 / 22
1왜 배우는가2핵심 원리3코드 예제4응용 변형 예제5자주 하는 실수 (Tip)6연습 문제7정리‹ 이전다음 ›

3. 코드 예제

실행 방법입니다. 외부 jar 는 필요 없습니다.

cmd
cd java-src\extension\22_performance
javac -encoding UTF-8 *.java
java -Dstdout.encoding=UTF-8 Main

Bench — 워밍업·죽은 코드 제거 방지 하네스

java
// Bench.measure: 워밍업 후 반복마다 나노초를 모아 분위수 계산
static void measure(String name, int warmupIters, int iters, Task task) {
    for (int i = 0; i < warmupIters; i++) {
        sink += task.run(); // 결과를 더해 죽은 코드 제거를 막는다
    }
    long[] samples = new long[iters];
    for (int i = 0; i < iters; i++) {
        long start = System.nanoTime();
        sink += task.run();
        samples[i] = System.nanoTime() - start;
    }
    Arrays.sort(samples);
    // p50·p95·p99·평균을 마이크로초 단위로 출력
}

sink 는 static long 필드로, 벤치마크 결과를 계속 더합니다. JIT 가 "아무도 쓰지 않는 계산"이라 판단해 지워버리는 것을 막는 최소한의 장치입니다.

데모 실행 결과

text
=== 1. String + vs StringBuilder (10만 회 누적) ===
String plus             p50=3686671.1us ...   ← 약 3.7초
StringBuilder           p50=   5971.7us ...   ← 약 6ms
=== 2. ArrayList.contains vs HashSet.contains (1만 건 조회) ===
ArrayList.contains      p50= 536169.6us ...   ← 약 536ms
HashSet.contains        p50=   5348.5us ...   ← 약 5ms
=== 3. 워밍업 유무에 따른 첫 반복 시간(JIT) ===
워밍업 0회(콜드)          p50=   3363.3us p95=11028.1us
워밍업 2000회(웜)         p50=    317.6us p95=  737.5us
=== 4. 자체 부하 테스트 (동시 20, 총 200 요청, 각 50ms) ===
요청 200건, 동시 20, p50=80.0ms p95=1608.2ms TPS=74.3
=== 5. JFR 기록 명령 (출력만, 실행 안 함) ===
jcmd <PID> JFR.start name=app duration=60s filename=app.jfr
jcmd <PID> JFR.dump name=app filename=app_snapshot.jfr
jfr print --events jdk.CPULoad app.jfr

String + 는 매번 새 문자열을 복사해 만들어, 반복 횟수가 늘수록 O(n²)로 느려집니다. 10만 회에서 StringBuilder 대비 600배 이상 차이가 납니다. ArrayList.contains 도 같은 이유로 HashSet.contains 보다 100배 느립니다.

워밍업 유무 비교에서는 워밍업 후가 콜드보다 p50 기준 10배 빠릅니다. JIT 가 인터프리터 코드를 기계어로 바꾼 효과입니다. 실무 벤치마크에서 워밍업을 빼먹으면 이 차이만큼 결과가 왜곡됩니다.

부하 테스트는 p50 80ms 대비 p95 가 1.6초로 크게 벌어집니다. 로컬 루프백 환경에서 매 요청마다 새 커넥션을 맺을 때 생기는 지연 편차 때문으로, "평균만 보면 문제를 놓친다"는 2.2절 내용을 그대로 보여주는 예시입니다.

예제 직접 실행

아래 폴더를 JDK 21 로 컴파일하고 실행합니다. 외부 jar 를 쓰는 레슨은 java-src/lib 를 클래스패스에 넣습니다.

cd java-src\extension\22_performance
javac -encoding UTF-8 *.java && java Main

:: 외부 jar 가 필요한 레슨
javac -encoding UTF-8 -cp "..\..\lib\*;." *.java && java -cp "..\..\lib\*;." Main
코드 예제
  • Bench — 워밍업·죽은 코드 제거 방지 하네스
  • 데모 실행 결과
이전 섹션2 핵심 원리3 / 7다음 섹션4 응용 변형 예제