
불필요한 객체 생성은 왜 피해야 할까?
똑같은 기능의 객체를 매번 생성하기 보다는 객체 하나를 재사용하는 편이 나을 때가 많다. 재사용은 빠르고 세련되다. 특히 불변 객체(아이템 17) 은 언제든 재사용할 수 있다.
방법 1. String 객체는 새로 생성하지 말자
// 1. 잘못된 예
String s = new String("bikini");
// 2. 옳은 예
String s = "bikini";
1번의 예시는 실행될 때마다 새로운 String
객체를 생성한다. 반복문이나 빈번히 호출되는 메서드의 경우 인스턴스가 수백만개 생성될 수 있다.
이러한 경우에는 새로운 인스턴스를 매번 생성하는 대신 하나의 String
인스턴스를 사용하자. 이 방식을 사용한다면 같은 가상 머신 안에서 똑같은 문자열 리터럴을 사용하는 모든 코드가 같은 객체를 재사용함이 보장된다.
방법 2. 정적 팩터리 메서드를 사용한다.
정적 팩터리 메서드를 제공하는 불변 클래스에서는 정적 팩터리 메서드를 사용해 불필요한 객체 생성을 피할 수 있다. 생성 비용이 비싼 객체도 있으므로 이러한 경우는 캐싱하여 재사용하길 권한다.
방법 3. String.matches 메서드를 Pattern 인스턴스로 대체하자.
String.matches
는 정규표현식으로 문자열 형태를 확인하는 가장 쉬운 방법이지만, 성능이 중요한 상황에서 반복해 사용하기엔 적합하지 않다. 이 메서드는 내부에서 정규표현식용 Pattern
인스턴스를 생성하고 한번 쓰고 버려져 가비지 컬렉션의 대상이 된다. 또한, Pattern
은 유한 상태 머신을 만들기 때문에 인스턴스 생성 비용이 높다.
따라서, 불변인 Pattern
인스턴스를 생성해 캐싱해두고, 계속해서 이 인스턴스를 재활용하자. 객체가 불변이면 재사용해도 안전함이 명백하다.
방법 4. 오박싱(auto boxing) 사용을 줄이자.
오토박싱은 기본 타입과 그에 대응하는 박싱된 기본 타입의 구분을 흐려주지만, 완전히 없애주는 것은 아니다. 의미상은 별다름이 없지만 성능은 아니다.
// 샘플 코드
위의 예시에서는 매번 Long
타입의 인스턴스를 생성한다. 박싱된 타입보다는 기본 타입을 사용하고, 의도치 않은 오토박싱이 숨어들지 않도록 주의하자.
그 외 알아둘 것
“객체 생성은 비싸니 피해야 한다”라는 뜻이 아니다. 요즘 JVM에서는 작은 객체를 생성하고 회수하는 동작이 부담되지 않는다. 프로그램의 명확성, 간결성, 기능을 위해 객체를 추가하는 것은 일반적으로 좋은 일이다.
또한, 아주 무거운 객체가 아니고서야 여러분의 객체 풀을 따로 만들지 말자. 요즘 JVM 가비지 컬렉터는 상당히 잘 최적화되어서 가벼운 객체용을 다룰 때는 객체 풀보다 훨씬 더 빠르다.
이번 아이템은 방어적 복사( defensive copy)와 대비해서 피해가 훨씬 크다. 하지만, 방어적 복사에 실패하면 언제 터져 나올지 모르는 버그와 보안 구멍으로 이어지지만, 필요한 객체 생성은 그저 코드 형태와 성능에만 영향을 준다.
'Java > Effective Java' 카테고리의 다른 글
Effective Java 9. try-with-resources를 사용하자 (0) | 2022.10.04 |
---|---|
Effective Java 7. 다 쓴 객체 참조를 해제하라 (0) | 2022.01.22 |
Effective Java 5. 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라 (0) | 2022.01.04 |
Effective Java 4. 인스턴스화를 막으려거든 private 생성자를 사용하라 (0) | 2022.01.02 |
Effective Java 3. 생성자나 열거 타입으로 싱글턴임을 보증하라 (0) | 2021.12.28 |