블로그들을 보다보면 Optional은 비싸다고 한다는데 얼마나 비싼것일까?
이런 의문을 가지고 간단하게 리서칭 및 테스트를 진행해보았다.
Optional Cost에 대한 블로깅
https://homes.cs.washington.edu/~mernst/advice/nothing-is-better-than-optional.html
Nothing is better than the Optional type
Nothing is better than the Optional type by Michael Ernst June 23, 2018 (和訳, Japanese translation, Java Magazine version) JDK 8 introduced the Optional class, a container that is either empty or contains a non-null value. Optional has numerous problems
homes.cs.washington.edu
http://pkolaczk.github.io/overhead-of-optional/
Overhead of Returning Optional Values in Java and Rust | Piotr Kołaczkowski
October 16, 2021 Some programming languages like Java or Scala offer more than one way to express a concept of “lack of value”. Traditionally, a special null value is used to denote references that don’t reference any value at all. However, over time
pkolaczk.github.io
https://dzone.com/articles/using-optional-correctly-is-not-optional
26 Reasons Why Using Optional Correctly Is Not Optional
We take a look at the top 25 most important concepts to keep in mind when working with Optionals in Java, focusing on null variables and more.
dzone.com
https://velog.io/@seanee3670/Optional-%EA%B3%BC-%EC%84%B1%EB%8A%A5
Optional 과 성능, 그리고 pros and cons
문득 그런 생각이 들었다.
velog.io
성능 차이가 있다 vs 성능 차이가 없다. 로 팽팽한 편
벤치마킹을 하여 직접 성능 차이를 느껴보자.
# 테스트
테스트 케이스를 구성할 때 여러 필드를 가진 복잡한 객체보다는 간단한 값으로 테스트를 구성. 불필요한 오버헤드를 최소화하도록 의도.
벤치마킹을 위해 JMH (Java Microbenchmark Harness) 라이브러리 이용.
- 1부터 10억까지 덧셈하는 케이스로 테스트하였으며, 평균 시간, 메모리 사용량을 벤치마킹
- 총 5개의 케이스에 대해 벤치마킹
- 1 ~ 10억까지 덧셈 - sumLong()
- 1 ~ 10억까지 Optional.ofNullable()으로 치환해서 덧셈 - sumOptional()
- 1 ~ 10억까지 OptionalLong을 이용하여 불필요한 박싱/언박싱을 최소화하기 위해 사용 - sumOptionalPrimitive()
- 1 ~ 10억까지 10억개 중 66% 비율만 덧셈 - sumLongWithNull()
- 1 ~ 10억까지 10억개 중 66% 비율만 Optional.ofNullable()으로 치환해서 덧셈 - sumOptionalNulls()
# 테스트 결과
테스트한 코드는 링크로 대체 (_ _)
https://github.com/ohtaeg/TIL/blob/master/java/src/main/java/optional/OptionalBenchmark.java
Benchmark Mode Cnt Score Error Units
OptionalBenchmark.sumLong avgt 5 267.153 ± 11.951 ms/op
OptionalBenchmark.sumLong:gc.alloc.rate avgt 5 ≈ 10⁻⁴ MB/sec
OptionalBenchmark.sumLong:gc.alloc.rate.norm avgt 5 14.562 ± 1.437 B/op
OptionalBenchmark.sumLong:gc.count avgt 5 ≈ 0 counts
OptionalBenchmark.sumLongWithNull avgt 5 424.664 ± 18.002 ms/op
OptionalBenchmark.sumLongWithNull:gc.alloc.rate avgt 5 ≈ 10⁻⁴ MB/sec
OptionalBenchmark.sumLongWithNull:gc.alloc.rate.norm avgt 5 22.933 ± 2.296 B/op
OptionalBenchmark.sumLongWithNull:gc.count avgt 5 ≈ 0 counts
OptionalBenchmark.sumOptional avgt 5 257.686 ± 10.979 ms/op
OptionalBenchmark.sumOptional:gc.alloc.rate avgt 5 ≈ 10⁻⁴ MB/sec
OptionalBenchmark.sumOptional:gc.alloc.rate.norm avgt 5 13.973 ± 1.840 B/op
OptionalBenchmark.sumOptional:gc.count avgt 5 ≈ 0 counts
OptionalBenchmark.sumOptionalNulls avgt 5 1292.880 ± 11.567 ms/op
OptionalBenchmark.sumOptionalNulls:gc.alloc.rate avgt 5 9835.037 ± 88.169 MB/sec
OptionalBenchmark.sumOptionalNulls:gc.alloc.rate.norm avgt 5 13333332380.800 ± 6.888 B/op
OptionalBenchmark.sumOptionalNulls:gc.count avgt 5 1515.000 counts
OptionalBenchmark.sumOptionalNulls:gc.time avgt 5 445.000 ms
OptionalBenchmark.sumOptionalPrimitive avgt 5 265.150 ± 0.252 ms/op
OptionalBenchmark.sumOptionalPrimitive:gc.alloc.rate avgt 5 ≈ 10⁻⁴ MB/sec
OptionalBenchmark.sumOptionalPrimitive:gc.alloc.rate.norm avgt 5 14.484 ± 1.450 B/op
OptionalBenchmark.sumOptionalPrimitive:gc.count avgt 5 ≈ 0 counts
위 결과들을 요약하면 아래와 같다.
메서드 | 평균 실행 시간 (ms/op) | 메모리 할당률 (B/op) | GC 횟수 | 요약 |
sumLong() | 267.153 | 14.562 | 0 | 박싱 없음 |
sumOptional() | 257.686 | 13.973 | 0 | 박싱 있음 Optional.ofNullable 사용 예상보다 빠름 |
sumOptionalPrimitive() | 265.150 | 14.484 | 0 | 박싱 없음 OptionalLong 사용 |
sumLongWithNull() | 424.664 | 22.933 | 0 | 박싱 있음 null 체크와 박싱된 Long 객체 반복 사용으로 인해 조금 성능 차이 있음. |
sumOptionalNulls() | 1292.880 | 13,333,332,380.8 | 1515 | GC 유발 처리 속도와 메모리 사용률 높음 |
상황과 환경에 따라 테스트 결과가 다르겠지만, 위 테스트 결과로는 Optional을 어떻게 사용하냐에 따라 성능 차이가 존재하는 것 같다.
Optional 자체가 항상 느린 것은 아니기에 적절하게 사용하면 성능 차이가 없을수도 있다.
하지만 루프 등등 대량의 데이터를 많이 다룰 때는 위와 같이 GC 부담이 커지고 성능도 저하된다.
작은 차이가 누적되면 큰 성능 차이로 만들 수도 있다.
'java' 카테고리의 다른 글
[자바 병렬 프로그래밍] Lock에 대한 궁금점 (2) | 2021.12.21 |
---|---|
HashMap 내부는 충돌시 언제 트리 구조로 변경될까? (7) | 2021.02.02 |
compareTo()를 재정의 시 equals()를 왜 함께 재정의 해야할까? (0) | 2021.01.25 |
댓글