[06] 불필요한 객체 생성을 피하라
핵심 내용
딱히 쉽게 해석할 여지가 없다. 말 그대로 쓸데없이 객체 생성 더 해서 메모리 낭비 및 성능 하락 시키지 말라는 내용이다.
필요한데 생성하지 말라고 한다면 어떻게 하라는 것인가
아이템 1 에서 언급 한 것 처럼 정적 팩터리 메서드를 통해서 기존에 생성해둔 객체를 재사용하라고 권하고 있다. 재미있는 부분은 자주 사용되는 유틸 종류의 객체를 static 에 올려놓고 사용하는 경우가 많은데, 이 때 굳이 레이지 로딩 처리를 하지 말라는 것이다.(아이템 67) 트레이드 오프를 따지면 굳이 복잡도를 더 올린다고 판단하는 것 같다.
"hello" vs new String("hello") 뭐가 다를까
문자열 인터닝을 알고 있다면 쉽게 이해할 수 있다. 후자의 경우 문자열 인터닝을 피해서 생성하게 된다. 즉, 이미 "hello" 가 문자열 풀에 들어가 있다고 하더라도 후자의 방식으로 문자열을 생성할 경우 새로운 객체가 생성된다. 어차피 같은 문자열인데 쓸데없이 객체를 하나 더 만든 것이다.
성능 차이가 많이 날까? 아주 많이 난다.
아래 코드로는 76~77ms 이 나오고 있다. 문자열 풀에서 꺼내 쓰는 것을 피하고 새로운 객체를 일부러 만들게 했다.
반면에 아래 코드는 1ms 이 찍힌다. 그냥 숫자만으로 속도가 70배 이상 차이가 난다.
오토박싱과 언박싱
래퍼클래스가 감싸는 역할을 하는 것을 생각하면 래퍼로 자동으로 감싸 주는 것을 오토박싱이라고 하고 래퍼 클래스를 원시형으로 자동으로 변환해주는 것이 언박싱이다.
오토박싱(autoboxing)은 자바의 기본 데이터 타입을 해당 타입의 래퍼 클래스(wrapper class) 객체로 자동 변환하는 프로세스를 의미합니다. 이와 반대로, 언박싱(unboxing)은 래퍼 클래스 객체를 해당 기본 데이터 타입으로 자동 변환하는 프로세스를 말합니다.
오토박싱과 언박싱은 Java 5 (JDK 1.5)에서 도입되었으며, 프로그래머가 명시적으로 기본 타입과 래퍼 타입 간의 변환을 처리하는 코드를 줄이도록 도와줍니다.
오토박싱을 조심하자
이 부분은 내가 실무에서 똑같이 실수할 수 있을 것 같아서 따로 정리한다.
불필요한 객체를 만들어내는 또 다른 예로 오토박싱을 들 수 있다. 오토박싱은 프로그래머가 기본 타입과 박싱된 기본 타입을 섞어 쓸 때 자동으로 상호 변환해주는 기술이다.
오토박싱은 기본 타입과 그에 대응하는 박싱된 기본 타입의 구분을 흐려주지만, 완전히 없애주는 것은 아니다.
위 코드에서 반복문이 1회 실행 될 때마다 int i 가 Long 에의 덧셈을 위해서 Long 으로 오토박싱 되고 있다. 매번 Long 클래스가 힙에 할당되고 있다. 사실 더 구체적으로 보자면 아래와 같은 맥락이 숨어있다.
int
값i
는long
값으로 프로모션됩니다.그 결과는
autoboxSum
의long
값과 더해집니다.덧셈의 결과는
Long
객체로 오토박싱되어autoboxSum
에 저장됩니다.
현재 위 코드는 2744ms 정도가 나온다.
아래 코드로 오토박싱을 피하고 원하는 연산은 그대로 처리해보자.
720ms 이 나온다. autoboxSum 의 타입을 Long 대신 long 으로 바꿔주었을 뿐인데 대략 4배 정도 속도 차이가 나고 있다.
그렇다고 객체 생성을 하는 것에 너무 보수적이지는 말자
책에서 말미에 강조하는 부분이 있는데 JVM 의 GC 의 역량이다. '요즘의' JVM 에게는 GC 가 잘 알아서 회수를 하니까 객체 생성에 너무 보수적으로 굴다가 괜히 코드 가독성을 떨어트린다던가 버그를 만들지 말라는 것이다.
특히 아주 무거운 객체가 아닌 다음에야 단순히 객체 생성을 피하고자 pool 을 굳이 만들지 마라고 하고 있다. DB 접속을 위한 스레드 풀 정도로 미리 만들어 놓는 것이 좋음이 명확하지 않은 이상 중복해서 만들어도 크게 성능에 문제가 없으니(=GC 가 알아서 메모리 해제를 하니까) 걱정 말라는 것이다.
같은 맥락에서 후에 나올 아이템에서 '방어적 복사'를 다루는 것 같은데, 특히 오류 방지를 위한 방어적 복사가 필요한 경우에 괜히 객체 생성 안하려고 보수적으로 굴다가 치명적인 실수를 하지 말고 알아서 잘(?) 하라고 강조하고 있다.
이게 아이템 50이라서 아직 진도가 닿지 않았는데 아무래도 얕은 복사로 인해 의도치 않은 버그 발생을 피하기 위해 이 경우 깊은 복사를 하도록 유의 하라는 내용으로 보인다.
Last updated