불필요한 객체 생성을 피하라

Choizz·2023년 7월 18일
0

이펙티브 자바

목록 보기
6/13

이펙티브 자바 내용 중 "불필요한 객체 생성을 피하라"에 관련한 내용을 포스팅하겠습니다.

자바 언어의 경우, 객체를 생성한 후 jvm에서 사용하지 않는 객체를 제거해줍니다. 그렇기 때문에, 저같은 경우 메모리에 대해서 크게 생각하지 않고 코딩을 하는 경우가 있습니다. 그래서 불필요한 객체를 생성하는 경우가 종종 있을 수 있습니다.

그렇다면, 대표적으로 어떤 경우에 불필요한 객체를 생성하게 될까요?


문자열

  • 보통 문자열을 리터럴로 생성할 때, 힙 메모리에 불변 객체로 하나만 존재하게 됩니다. 그래서, 같은 문자열을 사용할 때는 처음 생성된 문자열 하나만 반복해서 사용하게 됩니다.
String a = "test";
String b = "test";
(a == b는 true) -> 메모리 상에서 같은 문자열을 사용
  • 하지만, new 생성자를 이용해서 객체를 생성할 경우, 같은 문자열이라도 다른 문자열 객체 인스턴스가 생성되기 때문에 굳이 없어도 될 객체들이 생성되는 것입니다.
String b = new String("test");  
String c = new String("test"); 
(b == c는 false) -> b와 c는 다른 인스턴스이다.
  • 따라서, 문자열을 생성할 경우는 리터럴을 사용하는 것이 불필요한 객체를 생성하지 않는 방법일 것입니다.
    저번에 포스팅한 글을 참고하시면 좋을 것 같습니다. (참고)

정규식 관련

  • 정규식을 위한 객체를 생성하는 것은 생성 비용이 꽤 큽니다(cpu 사용이 큼). 반복해서 생성하는 것 보다는 캐싱해서 재사용하는 것이 효율적입니다.
  • 실제로 반복해서 컴파일 할 경우 '8436167 ns',
  • 캐싱해서 하는 경우 '10208 ns'의 시간이 걸리는 것을 확인할 수 있었습니다.
public class Test2 {
	
    // 미리 캐싱해서 static 영역에 저장시켜 놓음.
    private static final Pattern TEST = Pattern.compile(",|.|\\*|^");


    public static void main(String[] args) {

        long s = System.nanoTime();
        for (int i = 0; i < 1000; i++) {
            Pattern.compile(",|.|\\*|^"); //8436167 ns
            Pattern a = TEST; //10208 ns
        }
        long e = System.nanoTime();
        System.out.println(e - s);
    }
}
  • 문자열에 문자가 하나만 있다면(ex: ","), 정규 표현식을 컴파일하지 않고도 빠르게 처리가 되기 때문에 하나의 문자만 있다면 굳이 캐싱하지 않아도 됩니다.

오토 박싱

  • 오토 박싱이란, primitive 타입을 wrapper 타입으로 자동으로 상호 변환해주는 기술을 의미합니다.
  • primitive 타입을 wrapper 타입과 동시에 사용을 한다면 오토 박싱 과정에서 불필요한 객체가 생성될 수 있습니다.
public class Adder {

       public static void main(String[] args) {
            
              for(long i = 0 ; i < 1000; i++){
                	Long sum= 0L; //객체가 계속 생성됨.
                    long a = sum + i; 
              }
       }
}

정리

  • 객체 생성이 비싸니 최대한 피하는게 좋다는 것이 아니라, 불필요한 객체를 생성하지 말자는 의미라는 것을 기억해야 할 것 같습니다.

reference

profile
집중

1개의 댓글

comment-user-thumbnail
2023년 7월 18일

잘 봤습니다. 좋은 글 감사합니다.

답글 달기