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

✍️ OpenClawRadar📅 게시일: March 20, 2026🔗 Source
자바 성능 최적화: 코드를 느리게 만드는 8가지 안티패턴
Ad

안티 패턴 수정으로 인한 성능 개선

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가 캐리어를 고정
Ad

상세 예시 및 해결 방법

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

Ad

👀 See Also

클로드와 OpenAI 사용을 위한 모델 라우팅 기준선
Guides

클로드와 OpenAI 사용을 위한 모델 라우팅 기준선

한 개발자가 Claude Haiku 4.5, Sonnet 4.6, Opus 4.6 및 ChatGPT 5.3 Codex를 다양한 작업 유형에 사용하는 모델 라우팅 전략을 공유하며, 필요 시 GPT-5 Mini와 GPT-5.4로 폴백합니다.

OpenClawRadar
OpenClaw Docker 사용자: 깨진 Discord 및 채널 확장 기능을 수정하려면 커밋 0c926a2c5로 고정하세요.
Guides

OpenClaw Docker 사용자: 깨진 Discord 및 채널 확장 기능을 수정하려면 커밋 0c926a2c5로 고정하세요.

Docker를 통해 OpenClaw를 업데이트한 후 Discord, Signal, WhatsApp과 같은 채널 확장 기능이 모듈 가져오기 오류로 실패합니다. 이 문제는 커밋 d9c285e93과 두 번째 Docker 특정 버그에서 비롯됩니다. 안정적인 해결책을 위해 커밋 0c926a2c5로 고정하세요.

OpenClawRadar
MCP를 통해 기계적 작업을 DeepSeek V4 Flash에 오프로드하여 Claude 비용 60배 절감
Guides

MCP를 통해 기계적 작업을 DeepSeek V4 Flash에 오프로드하여 Claude 비용 60배 절감

한 Reddit 사용자가 파일 분류, JSON 재포맷, 필드 추출 작업을 간단한 MCP 도구와 CLAUDE.md 거부 목록 규칙을 통해 DeepSeek V4 Flash로 라우팅하여 Claude API 사용량을 60배 절감했습니다.

OpenClawRadar
종단 간 LLM 스택 추적: 키 입력부터 스트리밍된 토큰까지
Guides

종단 간 LLM 스택 추적: 키 입력부터 스트리밍된 토큰까지

소프트웨어 엔지니어가 LLM에 프롬프트를 보낼 때 스택의 모든 계층에서 발생하는 일을 추적하는 포괄적인 문서를 작성했습니다. 클라이언트 측 토큰 카운팅, 네트워크 프로토콜, API 게이트웨이, 안전 분류기, 토큰화, KV 캐시, 샘플링 파이프라인, 스트리밍 메커니즘을 다룹니다.

OpenClawRadar