반응형
■ 코드 성능 최적화 해보기
1. 프로파일링을 통한 병목 지점 파악
- 시간 측정 코드
long startTime = System.nanoTime(); myMethod(); long endTime = System.nanoTime(); System.out.println("실행 시간: " + (endTime - startTime) / 1000000 + "ms");
- 전문 프로파일링 도구: VisualVM, JProfiler, YourKit 활용
- 핵심: 전체 코드의 10%가 90%의 성능 문제를 일으키는 경우가 많음
2. 반복문 최적화
// 최적화 전
for (int i = 0; i < list.size(); i++) {
// 매번 list.size() 호출
}
// 최적화 후
int size = list.size();
for (int i = 0; i < size; i++) {
// size 한 번만 계산
}
// 더 나은 방법
for (Object item : list) {
// 향상된 for문 사용
}
3. 계산 결과 캐싱
public class CachedCalculator {
private Map<String, Double> cache = new HashMap<>();
public double calculate(String key) {
if (cache.containsKey(key)) {
return cache.get(key);
}
double result = heavyComputation(key);
cache.put(key, result);
return result;
}
}
4. 적절한 자료구조 선택
- 검색이 빈번할 때: HashMap, HashSet (O(1) 검색)
- 정렬이 중요할 때: TreeMap, TreeSet
- 순차 접근만 필요할 때: ArrayList
- 큐/스택 동작이 필요할 때: LinkedList, ArrayDeque
// 검색이 빈번한 경우 HashMap 활용
Map<String, Customer> customerMap = new HashMap<>();
customerMap.put(customer.getId(), customer);
Customer found = customerMap.get(targetId); // O(1) 검색
5. 문자열 처리 최적화
// 최적화 전
String result = "";
for (String s : strings) {
result += s; // 매번 새 String 객체 생성
}
// 최적화 후
StringBuilder builder = new StringBuilder();
for (String s : strings) {
builder.append(s);
}
String result = builder.toString();
■ 메모리 사용량 최적화 해보기
1. 적절한 데이터 타입 사용
대문자/ 소문자 한자의 차이가 크다!
// 최적화 전
Long[] array = new Long[1000000]; // 객체 타입, 더 많은 메모리 사용
// 최적화 후
long[] array = new long[1000000]; // 기본 타입, 메모리 효율적
2. 객체 재사용 (객체 풀링)
public class StringBuilderPool {
private final ThreadLocal<StringBuilder> builderPool =
ThreadLocal.withInitial(StringBuilder::new);
public String concatenate(List<String> strings) {
StringBuilder builder = builderPool.get();
builder.setLength(0); // 재사용 전 초기화
for (String s : strings) {
builder.append(s);
}
return builder.toString();
}
}
3. 메모리 누수 방지
// 메모리 누수 위험 있는 코드
public class EventManager {
private List<EventListener> listeners = new ArrayList<>();
public void addListener(EventListener listener) {
listeners.add(listener);
}
// 리스너 제거 메서드 없음 - 누수 발생
}
// 개선된 코드
public class EventManager {
private List<EventListener> listeners = new ArrayList<>();
public void addListener(EventListener listener) {
listeners.add(listener);
}
public void removeListener(EventListener listener) {
listeners.remove(listener);
}
}
4. 대용량 데이터 처리
// 청크 단위 처리
public void processLargeData(List<Data> allData) {
int chunkSize = 1000;
for (int i = 0; i < allData.size(); i += chunkSize) {
List<Data> chunk = allData.subList(
i, Math.min(i + chunkSize, allData.size())
);
processChunk(chunk);
}
}
■ 실전 최적화 기술
아직 잘 모르겠지만 일단 메모!
1. JVM 튜닝
# 힙 크기 설정
java -Xms1g -Xmx2g MyApplication
# G1 가비지 컬렉터 사용
java -XX:+UseG1GC MyApplication
# 메모리 사용 모니터링
jstat -gc <pid> 1000
2. 병렬 처리 활용
// 병렬 스트림 활용
List<Result> results = dataList.parallelStream()
.map(this::processItem)
.collect(Collectors.toList());
// CompletableFuture 활용
CompletableFuture<Result> future1 = CompletableFuture.supplyAsync(() -> processTask1());
CompletableFuture<Result> future2 = CompletableFuture.supplyAsync(() -> processTask2());
CompletableFuture.allOf(future1, future2).join();
3. 리소스 관리
// try-with-resources 사용
try (InputStream is = new FileInputStream(file);
OutputStream os = new FileOutputStream(output)) {
// 리소스 자동 정리
}
// 명시적 리소스 해제
ByteBuffer buffer = ByteBuffer.allocateDirect(4096);
// 사용 후
((DirectBuffer) buffer).cleaner().clean();
4. 효율적인 I/O 처리
// 버퍼링 I/O
try (BufferedReader reader = new BufferedReader(new FileReader(file), 8192)) {
// 8KB 버퍼로 읽기 - 성능 향상
}
// NIO 활용
FileChannel channel = FileChannel.open(Paths.get("large.dat"),
StandardOpenOption.READ);
ByteBuffer buffer = ByteBuffer.allocateDirect(4096);
while (channel.read(buffer) != -1) {
buffer.flip();
// 처리
buffer.clear();
}
■ 최적화 체크리스트
- 측정 먼저: 가정이 아닌 프로파일링을 통해 실제 병목 지점 확인
- 변경 후 재측정: 최적화 효과 검증
- 복잡성 대비 이득: 코드 복잡성 증가 대비 성능 향상 가치 평가
- 가독성 유지: 지나친 최적화로 유지보수성 희생 금지
- 핵심 로직 집중: 자주 실행되는 코드, 고비용 연산 집중 최적화
728x90
반응형
'Java' 카테고리의 다른 글
Spring Boot @Component, @Service, @Repository 차이점 정리 (0) | 2025.06.17 |
---|---|
Java Exception 처리 전략과 커스텀 예외 설계 (1) | 2025.06.08 |
boolean이랑 Boolean 뭐가 다를까? — Swagger 쓰다가 궁금해서 정리함 (0) | 2025.04.21 |
sts3 설치 시 압축풀기 오류 (0) | 2024.03.03 |
sts4 - spring boot 자동 리로드 시키는법 (0) | 2024.01.12 |