알고리즘/성능 분석 및 최적화
[Java] 기본형과 래퍼형 성능 비교
go_getter
2025. 2. 25. 21:07
테스트 방법
- 기본형과 래퍼형 모두 1000만 번의 반복문을 돌면서 연산을 진행한다.
- `System.nanoTime()` 메서드를 사용해서 반복문의 전, 후 사이의 시간을 기록한다.
1. 기본 자료형 int와 래퍼 클래스 Integer 연산 성능 테스트 코드
public class PrimitiveVsWrapperPerformance {
public static void main(String[] args) {
int iteration = 10_000_000; // 1000만 번 반복
// 기본형 int 연산 성능 테스트
long startTime1 = System.nanoTime();
int sum1 = 0;
for (int i = 0; i < iteration; i++) {
sum1 += i; // 기본형 연산
}
long endTime1 = System.nanoTime();
long primitiveTime = endTime1 - startTime1;
// 래퍼 클래스 Integer 연산 성능 테스트
long startTime2 = System.nanoTime();
Integer sum2 = 0;
for (int i = 0; i < iteration; i++) {
sum2 += i; // 오토박싱 & 언박싱 발생
}
long endTime2 = System.nanoTime();
long wrapperTime = endTime2 - startTime2;
// 결과 출력
System.out.println("기본형(int) 연산 시간: " + primitiveTime + " ns");
System.out.println("래퍼 클래스(Integer) 연산 시간: " + wrapperTime + " ns");
System.out.println("성능 차이 (배수): " + (double) wrapperTime / primitiveTime);
}
}
2. 기본 자료형 double과 직접 만든 래퍼형 MyDouble의 연산 성능 테스트 코드
2-1.
package chap1;
public class MyDouble {
double value;
public MyDouble(Double value){
this.value = value;
} //기본 생성자
public Double getValue(){
return value;
}
public void setValue(Double value){
this.value = value;
}
public void sumValue(int num){
this.value += num;
}
}
package chap1;
public class PrimitiveVsWrapperPerformance {
public static void main(String[] args) {
int iterator = 10_000_000;
// 기본 Double 성능 테스트
double sum1 = 0.0;
long startTime1 = System.nanoTime();
for(int i=0;i<iterator;i++){
sum1+=i;
}
long endTime1 = System.nanoTime();
long totalTime1 = endTime1 - startTime1;
// 내가 만든 MyDouble 성능 테스트
MyDouble sum2 = new MyDouble(0.0);
long startTime2 = System.nanoTime();
for(int i=0;i<iterator;i++){
sum2.sumValue(i);
}
long endTime2 = System.nanoTime();
long totalTime2 = endTime2 - startTime2;
System.out.println("totalTime1 = " + totalTime1);
System.out.println("totalTime2 = " + totalTime2);
}
}
// totalTime1 = 3683125
// totalTime2 = 24226291
계산했을 때, 래퍼형이 약 8배 가량 연산 시간이 오래 걸리는 것을 볼 수 있다.
객체를 언박싱해서 매개변수와 연산하고, 다시 그 값을 박싱하는 과정이 필요하기 때문이다.
래퍼형을 다른 방식으로 연산했을 때는 어떤 결과값이 있는지 확인해보자.
2-2.
// 직접 만든 Double 래퍼 클래스
class MyDouble {
private final double value;
public MyDouble(double value) {
this.value = value;
}
public double getValue() {
return value;
}
// 덧셈
public MyDouble add(MyDouble other) {
return new MyDouble(this.value + other.value);
}
@Override
public String toString() {
return String.valueOf(value);
}
}
public class DoubleWrapperPerformance {
public static void main(String[] args) {
int iteration = 10_000_000; // 1000만 번 반복
// 1. 기본형 double 연산
long startTime1 = System.nanoTime();
double sum1 = 0.0;
for (int i = 0; i < iteration; i++) {
sum1 += i * 1.1;
}
long endTime1 = System.nanoTime();
long primitiveTime = endTime1 - startTime1;
// 2. MyDouble 연산
long startTime3 = System.nanoTime();
MyDouble sum3 = new MyDouble(0.0);
for (int i = 0; i < iteration; i++) {
sum3 = sum3.add(new MyDouble(i * 1.1));
}
long endTime3 = System.nanoTime();
long myDoubleTime = endTime3 - startTime3;
// 결과 출력
System.out.println("기본형(double) 연산 시간: " + primitiveTime + " ns");
System.out.println("MyDouble 클래스 연산 시간: " + myDoubleTime + " ns");
System.out.println("MyDouble vs double 성능 차이: " + (double) myDoubleTime / primitiveTime);
}
}
// totalTime1 = 3717209
// totalTime2 = 103633583
이 경우는 약 28배 가량 래퍼형의 연산이 늦었다.
반복문 안에서 add 함수를 실행할 때마다 값을 박싱한 새로운 객체를 생성하고 , 기존의 객체와 새로운 객체를 언박싱하여 연산 후 다시 박싱하는 과정을 거치기 때문에 시간이 매우 지연된다.
그리고 이 코드는 시간의 문제 뿐만 아니라, 1000만 번의 반복문을 실행하면서 1000만 개의 새로운 객체를 생성하게 되면서 아래와 같은 상황을 발생시킬 수 있다.
1. 메모리 부족 (OutOfMemoryError)
- 힙 메모리를 초과하면 OutOfMemoryError 가 발생할 수 있다.
2. 가비지 컬렉션(GC) 부담 증가
- 가비지 컬렉션이 불필요한 객체를 자동으로 정리하지만, 객체가 너무 많으면 GC 작업이 잦아져 성능 저하가 발생할 수 있다.
- 잦은 GC → CPU 부하 증가 → 애플리케이션 응답성 저하
3. 메모리 단편화
- 많은 객체가 생성되고 해제되면서 메모리가 조각나게 되고, 결국 새로운 객체 할당 시 성능 저하의 원인이 될 수 있다.
4. 캐시 미스 증가
- 객체가 너무 많으면 CPU 캐시에서 데이터를 효율적으로 관리하기 어려워져 캐시 미스(cache miss) 빈도가 증가 → 실행 속도 저하
결론
래퍼 클래스는 아래 게시물과 같은 장점을 가지고 있지만, 위와 같은 시간 지연과 메모리 차지 등의 문제점을 일으키기 때문에 상황에 맞게 사용하도록 하자.
2025.02.25 - [언어/Java] - Wrapper 클래스
Wrapper 클래스
Wrapper Class기본 자료형을 객체로 감싸는 클래스즉, 래퍼 클래스는 객체 객체 또는 변수가 담겨있는, 참조형 변수는 데이터의 메모리 주소를 저장하므로, 해당 변수를 출력하면 데이터의 메모
go-getter1kim.tistory.com