Link
Today
Total
10-17 08:33
Archives
관리 메뉴

초보개발자 긍.응.성

(이펙티브 자바 3) 6. 불필요한 객체 생성을 피하라 본문

책 정리/이펙티브 자바 3

(이펙티브 자바 3) 6. 불필요한 객체 생성을 피하라

긍.응.성 2020. 7. 8. 23:30
반응형

똑같은 기능의 객체를 매번 생성하기보다는 객체 하나를 재사용하는 편이 나을 때가 많다. 재사용은 빠르고 세련되다. 특히 불변 객체는 언제든 재사용 가능하다.

아래는 불필요한 객체 생성의 극단 적인 예시이다.

String s = new String("I'm Son"); // 절대 사용하지 말 것!

위 문장은 실행될 때 마다 새로운 String 인스턴스를 새로 생성한다. 인자로 넣어주는 I'm Son과 정확히 같은 문자열을 쓸데없이 만들어 낸다.

String s = "I'm Son";

이 코드는 실행될때 하나의 String 인스턴스를 사용한다. 또한 이 방식을 사용한다면 같은 JVM안에서 이와 똑같은 문자열 리터럴을 사용하는 모든 코드가 같은 객체를 재사용한다.


생성자 대신 정적 팩토리 메서드로!

생성자 대신 정적 팩토리 메서드를 제공하는 불변 클래스에서는 정적 팩토리 메서드를 사용해 불필요한 객체 생성을 피할 수 있다.

예를 들어 생성자 Boolean(String) 대신 정적 팩토리 메서드의 Boolean.valueOf(String)을 사용하는 것이 낫다. 생성자를 호출할 때마다 새로운 객체를 만들지만, 팩토리 메서드는 그렇지 않다.


생성 비용이 아주 비싼 객체도

생성 비용이 아주 비싼 객체도 존재한다. 이런 비싼 객체가 반복해서 필요하다면 캐싱하여 쓰길 권한다.


오토 박싱은 자제하자

오토 박싱은 기본 타입과 그에 대응하는 박싱 된 기본 타입의 구분을 흐려주지만, 완전히 없애주지 않는다. 의미상 별다를 것 없이 보이지만 성능은 그렇지 않다.

private static long sum() {
    Long sum = 0L;
    for (long i = 0; i < Integer.MAX_VALUE; i++) {
        sum += i; // Long에 long을 더하며 오토박싱 발생
    }

    return sum;
}

위의 코드를 실행하면 변수 sum을 Long으로 선언해서 불필요한 Long 객체가 2^31개나 만들어 질것이다. 박싱 된 기본 타입보다는 기본 타입을 사용하고, 의도치 않은 오토 박싱이 숨어들지 않도록 주의하자.


객체 생성은 비싸니 피해야한다

이번 아이템에서 하려는 말은 객체 생성이 비싸니 피해야 한다 가 아니다. 요즘의 JVM에서는 별다른 일을 하지 않는 작은 객체를 생성하고 회수하는 일이 크게 부담이 아니다. 프로그램의 명확성, 간결성, 기능을 위해서 객체를 추가로 생성하는 것은 일반적으로 좋은 일이다.

대신, 아주 무거운 객체가 아닌 다음에서 객체 생성을 피하려고 커스텀 객체 풀(pool)을 만들지 않는 것이 좋다. DB 커넥션 같은 경우는 생성 비용이 워낙 비싸서 재사용하는 편이 낫지만, 일반적으로 자체 객체 풀은 코드를 헷갈리게 만들고 메모리 사용량을 늘리고 성능을 떨어뜨린다.


방어적 복사 (defensive copy)

방어적 복사는 생성자 인자로 받은 객체를 복사하는 방법이다. 방어적 복사는 취약점이 있는 객체에 대해 방어적 복사본을 만들고, 이 복사본으로 유효성을 검사하도록 한다. 방어적 복사를 실행하는 이유는 멀티스레딩 환경에서 원본 객체의 유효성을 검사하고 복사본을 만드는 찰나의 순간에 다른 스레드가 원본 객체를 수정할 위험이 있기 때문이다.

방어적 복사가 필요한 상황에서는 객체를 재사용했을 때의 피해가 (코드 형태와 성능), 필요 없는 객체를 반복 생성했을 때의 피해(버그와 보안적 문제) 보다 훨씬 크기 때문에 객체 생성을 해주는 것이 더 좋다.

반응형
Comments