비교할 문제
String 결합 성능에서 확인할 질문은 반복문 안 String +와 StringBuilder.append의 할당 차이는 언제 커지는가입니다. 완전히 같은 문자열과 encoding 전 단계 결과를 반환하게 하고 작은 고정식과 반복 누적을 분리합니다. 결과값, 순서, 오류 처리와 부수 효과가 다르면 같은 성능 비교가 아닙니다. 먼저 두 후보가 같은 일을 하는지 작은 입력으로 확인합니다.
원인 분석과 재현
반복문에서 immutable String을 계속 +로 누적하면 중간 복사가 늘 수 있지만 한 표현식의 결합은 compiler가 최적화할 수 있습니다.
결합 10회·1,000회, 짧은 문자열·Unicode에서 JDK version, allocation rate와 GC를 JMH로 측정합니다. runtime version, 운영체제, CPU와 memory 제한도 결과와 함께 기록합니다.
비교 질문은 반복문 안 String +와 StringBuilder.append의 할당 차이는 언제 커지는가입니다.
| 후보 | 유리한 조건 | 함께 치르는 비용 |
|---|---|---|
+ 고정식 |
짧고 고정된 표현 | compiler가 최적화할 수 있어 반복 누적과 결과가 다름 |
+ 반복 누적 |
아주 작은 횟수 | 중간 String 복사와 allocation이 반복될 수 있음 |
| StringBuilder | 반복·조건부 조립 | capacity와 공유 범위를 잘못 잡으면 memory·동시성 비용 |
@State(Scope.Thread)
public class StringBenchmark {
@Param({"10", "1000"}) int size;
@Benchmark public String plusInLoop() {
String result = ""; for (int i = 0; i < size; i++) result += i; return result;
}
@Benchmark public String builder() {
StringBuilder result = new StringBuilder(); for (int i = 0; i < size; i++) result.append(i); return result.toString();
}
}
// 예: -wi 5 -i 10 -f 3. 작은 고정식의 +와 반복문 안 누적은 별도 사례입니다.
해결 방안과 판정
warm-up과 측정 구간을 나누고 여러 번 반복합니다. 서비스 지연은 median과 p95를, 처리량 비교는 단위 시간당 완료 수와 오류율을 함께 기록합니다. CPU time, allocation, RSS·heap, GC, I/O 중 이 작업에 직접 관련된 지표만 선택합니다. 가독성이 좋은 짧은 +까지 일괄 교체하지 않습니다. 반복 횟수와 allocation profile에서 차이가 확인되는 경로에 StringBuilder를 사용합니다.
차이가 반복 실행의 흔들림보다 작다면 더 단순하고 읽기 쉬운 구현을 선택합니다. 차이가 충분히 크더라도 실제 요청 전체의 지연과 자원 사용이 개선되는지 확인한 뒤 적용합니다.
공식 문서와 적용 범위
문서의 기본값과 동작은 version에 따라 달라질 수 있습니다. 현재 JDK/JVM version, 실행 옵션, collector, runtime 환경과 실제 memory 사용 패턴에서 다시 확인합니다.