자바 성능 최적화: 코드를 느리게 만드는 8가지 안티패턴

안티 패턴 수정으로 인한 성능 개선
Jonathan Vogel이 구축한 Java 주문 처리 애플리케이션은 초기 경과 시간 1,198ms, 초당 85,000건 처리, 1GB 이상 힙 사용, 19회 GC 일시 정지 성능을 보였습니다. 아키텍처 변경이나 JDK 업데이트 없이 8가지 안티 패턴을 수정한 후, 성능이 경과 시간 239ms, 초당 419,000건 처리, 139MB 힙 사용, 4회 GC 일시 정지로 개선되었습니다. 이는 처리량 5배 증가, 힙 사용량 87% 감소, GC 일시 정지 79% 감소를 의미합니다.
수정해야 할 8가지 Java 성능 안티 패턴
- 루프 내 문자열 연결 - 불변성으로 인한 O(n²) 복사
- 루프 내 O(n²) 스트림 반복 - 요소마다 전체 목록 스트리밍
- 핫 경로에서의 String.format() 사용 - 가장 느린 문자열 빌더, 매 호출마다 형식 파싱
- 핫 경로에서의 오토박싱 - 수백만 개의 일회용 래퍼 객체 생성
- 제어 흐름을 위한 예외 사용 - fillInStackTrace()가 전체 호출 스택을 순회
- 너무 광범위한 동기화 - 하나의 락이 병목 현상이 됨
- 재사용 가능한 객체 재생성 - 호출마다 ObjectMapper, DateTimeFormatter, Gson 생성
- 가상 스레드 고정 (JDK 21-23) - synchronized + 블로킹 I/O가 캐리어를 고정
상세 예시 및 해결 방법
1. 루프 내 문자열 연결
문제 코드:
String report = "";
for (String line : logLines) {
report = report + line + "\n";
}문자열 불변성으로 인해 O(n²) 복사가 발생합니다. BellSoft JMH 벤치마크에 따르면 n이 4배 증가할 때 루프 연결 속도는 7배 이상 느려집니다.
해결 방법:
StringBuilder sb = new StringBuilder();
for (String line : logLines) {
sb.append(line).append("\n");
}
String report = sb.toString();참고: JDK 9부터 컴파일러는 "Order: " + id + " total: " + amount와 같은 단일 라인 연결을 최적화하지만, 이 최적화는 루프 내부로 이어지지 않습니다.
2. 루프 내 스트림으로 인한 의도치 않은 O(n²)
문제 코드:
for (Order order : orders) {
int hour = order.timestamp().atZone(ZoneId.systemDefault()).getHour();
long countForHour = orders.stream()
.filter(o -> o.timestamp().atZone(ZoneId.systemDefault()).getHour() == hour)
.count();
ordersByHour.put(hour, countForHour);
}이 패턴은 JFR 기록에서 CPU 스택 샘플의 거의 71%를 차지했습니다. 10,000건의 주문으로 단일 패스 대신 1억 건의 비교를 수행합니다.
해결 방법:
for (Order order : orders) {
int hour = order.timestamp().atZone(ZoneId.systemDefault()).getHour();
ordersByHour.merge(hour, 1L, Long::sum);
}이는 단일 패스로 O(n) 성능을 제공합니다. 단일 스트림 파이프라인에서 Collectors.groupingBy(... Collectors.counting())을 사용할 수도 있습니다.
이 글은 3부작 Java 성능 최적화 시리즈의 1부이며, 2부와 3부는 곧 출시될 예정입니다. 2부에서는 화염 그래프와 실제로 핫했던 메서드를 포함하여 이러한 수치 뒤의 프로파일링 데이터를 살펴볼 것입니다.
📖 전체 Source 읽기: HN AI Agents
👀 See Also

작은 로컬 모델에서 코딩 에이전트를 실행할 때 발생하는 문제점
7B 미만 모델로 다중 파일 작업을 테스트하면서 발견한 실제 실패 지점: 마크다운 펜스, 구조화된 출력 신뢰성, 파일 편집 오류, 읽기/쓰기 작업 분류.

RTX 3090에서 Qwen 3.6 27B/35B 최적화: 플래그, 양자화 및 자동 라우팅
한 사용자가 RTX 3090(24GB)에서 Qwen 3.6 27B 및 35B GGUF 모델을 위한 llama-server 플래그를 공유하며, 35B의 느린 속도와 27B의 불안정한 코드 출력을 보고합니다. 게시물은 더 나은 양자화, 플래그 튜닝, 자동 모델 전환에 대한 조언을 구합니다.

Claude Code v2.1.36: Opus 4.6에 빠른 모드가 추가되었습니다
Anthropic이 Claude Code v2.1.36을 출시하며 최신 Opus 4.6 모델에 Fast Mode 지원을 추가해 코드 생성 및 분석 속도를 크게 향상시켰습니다.

OpenClaw Ollama 클라우드: 누락된 모델 및 닥터 삭제 버그를 위한 3계층 수정
OpenClaw를 Ollama Cloud 모델과 함께 새로 설치했는데 kimi-k2.5만 작동하고 설정이 사라지는 문제가 발생했습니다. 원인은 공급자 목록 누락, name 필드 필요, 'openclaw doctor --fix'가 공급자 블록을 삭제하기 때문입니다. baseUrl을 명시적으로 추가하면 삭제를 막을 수 있습니다.