Java/Java 문법

[Java] 스트림에서 오토박싱 (박싱, 언방식)이 일어나는 이유

민돌v 2022. 9. 16. 10:24

 

스트림 병렬처리를 진행할 때, paraller Stream 이 순차적인 iterate(반복자) 보다 성능이 느리게 나오는 경우가 있습니다.

 

❓ 스트림 병렬처리의 성능이 낮게나오는 이유 중 하나로,

기본형(원시 타입) 특화되지 않은 스트림을 초러할 때 수반되는 오토박싱, 언방식 등의 오버헤드를 수반하기 때문이다.

 

라는 이유가 언급되었고, 그렇다면 스트림에서 왜 오토박싱이 일어나는지 잊어먹지 않기위해 정리합니다.

 

 

📗 요약 : 제네릭 때문에

 


 

자바 Stream 에서 내부적으로 오토박싱이(auto boxing) 일어나는 이유

 

📌 modern java in action 103 쪽을 보면

 

이유 1

👏🏻 함수형 인터페이스들에 제네릭 파라미터가 쓰여져있고, Java 에서 generice 은 참조형만 사용할 수 있다고 합니다. (제네릭 내부 구현상)

 

  1. 그렇기 때문에 자바에서는 기본형을 참조형으로 바꾸는 오토박싱이 일어나고,
  2. 기본형을 제넥릭에서 사용하기 위한 참조형 타입으로 박싱하고,
  3. 다시 언박싱해서 내보내는 일련의 과정이 추가되기 때문에 병렬 스트림에서 이에 대한 오버헤드가 일어날 수 있다..!

 

로 이해가 되는 것 같습니다.

 

 

이유 2

👏🏻  머,, 이유2 까지는 아니구 동일한 이야긴데 Stream 내부적으로보면, Stream Interface 도 제네릭 파라미터로 정의가 되어있습니다.

public interface Stream<T> extends BaseStream<T, Stream<T>> {

	...
    
 }

 

이처럼 Stream API 는 데이터가 객체라는 것을 기본 전제로 구현이 되어있기 때문에

기본형 타입(primitve type) 의 사용시, 내부적으로 오토박싱이 일어나는 이유였습니다!!

 

 


예시

오토박싱이 일어나는 Stream

➡️ 받아온 파라미터 숫자 n 까지의 합을 병렬 스트림을 이용해 구하는 로직입니다.

public long parallelSum(long n) {
    return Stream.iterate(1L, i -> i + 1)
        .limit(n)
        .parallel()
        .reduce(0L, Long::sum);
}

기본형 원시타입 long 이 파리미터로 들어오기 때문에 오토박싱 오버헤드를 수반합니다.


 

오토박싱이 일어나지 않도록 성능을 개서한 Stream

➡️  Stream API 에서는 기본형 (long, int, double ..) 특화 스트림을 별도로 제공합니다. 

  •  DoubleStream 
  •  IntStream 
  •  LongStream
public long parallelSum(long n) {
    return LongStream.rangeClosed(1, n)
        .parallel()
        .reduce(0L, Long::sum);
}

 

 

아래처럼, LongStream 의 rangeClosed 메소드는 기본형타입을 다루기 때문에 오토박싱이 일어나지 않습니다..!

public static LongStream rangeClosed(long startInclusive, final long endInclusive) {
    if (startInclusive > endInclusive) {
        return empty();
    } else if (endInclusive - startInclusive + 1 <= 0) {
        // Size of range > Long.MAX_VALUE
        // Split the range in two and concatenate
        // Note: if the range is [Long.MIN_VALUE, Long.MAX_VALUE] then
        // the lower range, [Long.MIN_VALUE, 0), and upper range,
        // [0, Long.MAX_VALUE], will both be further split in two
        long m = startInclusive + Long.divideUnsigned(endInclusive - startInclusive, 2) + 1;
        return concat(range(startInclusive, m), rangeClosed(m, endInclusive));
    } else {
        return StreamSupport.longStream(
                new Streams.RangeLongSpliterator(startInclusive, endInclusive, true), false);
    }
}

 

 

 

 

오토 박싱 ㅎ&nbsp; ㅎ

참고 : 모던 자바 인 액션 103쪽