티스토리 뷰
728x90
반응형
불필요한 객체 생성을 피하라
- 여기서 말하는 불필요한 객체란 무엇일까?
- 아래 예제를 보면 String 타입의 변수 a, b, c는 모두 "Hello World"라는 문자열을 가지게 됩니다. 하지만 이 세 문자열이 참조하는 주소값은 모두 다릅니다. 동일한 문자열을 이처럼 여러개로 중복 생성하는 것은 메모리 낭비입니다.
- String Constant Pool에 대하여
String a = new String("Hello World");
String b = new String("Hello World");
String c = new String("Hello World");
💡그럼 어떻게 사용해야 불필요한 객체 생성을 피할 수 있을까요?
- 아래 예제를 보면 리터럴로 선언을 해 놓으면 컴파일 시점에서 상수풀에 해당 String 인스턴스를 저장하며, 동일한 리터럴이 있는 경우에는 같은 주소값을 가지게 됩니다. 그렇기 때문에 메모리 낭비가 발생하지 않게되고 같은 객체를 재사용할 수 있습니다.
String a = "Hello World";
String b = "Hello World";
String c = "Hello World";
💡Boolean(String) vs Boolean.valueOf(String)
- 아래는 Boolean 클래스를 살펴본 것입니다. Boolean(String) 생성자 대신 Boolean.valueOf(String)을 사용하는게 더 좋습니다.
- Boolean(String)은 호출시점에 항상 새로운 객체를 만들지만 팩토리 메서드는 그렇지 않습니다.
public final class Boolean implements java.io.Serializable, Comparable<Boolean> {
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
/**
* Allocates a {@code Boolean} object representing the value
* {@code true} if the string argument is not {@code null}
* and is equal, ignoring case, to the string {@code "true"}.
* Otherwise, allocates a {@code Boolean} object representing the
* value {@code false}.
*
* @param s the string to be converted to a {@code Boolean}.
*
* @deprecated
* It is rarely appropriate to use this constructor.
* Use {@link #parseBoolean(String)} to convert a string to a
* {@code boolean} primitive, or use {@link #valueOf(String)}
* to convert a string to a {@code Boolean} object.
*/
@Deprecated(since="9")
public Boolean(String s) {
this(parseBoolean(s));
}
public static Boolean valueOf(String s) {
return parseBoolean(s) ? TRUE : FALSE;
}
생략...
}
💡비싼 객체
- 객체 생성 비용이 비싼 객체도 가끔 있습니다. 이런 비싼 객체가 반복되서 필요하다면 캐싱해서 재사용하는 것이 중요합니다. 하지만 자신이 만든 객체가 비싼 객체인지 판단하기는 어렵습니다.
- 자바에서는 대표적으로 정규표현식용 클래스인 Pattern 클래스는 생성비용이 비싼 클래스입니다. String 클래스의 matches 메서드를 사용하게 되면 내부적으로 Pattern 인스턴스를 만들어 한번 사용하고 바로 버려져 GC의 대상이 됩니다.
- 주의점 - 객체가 불변이라면 재사용해도 문제가 없습니다.
public class StringUtils {
private static final Pattern ROMAN = Pattern.compile("^(?=.)M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");
// 안좋은 방법
static boolean isRomanNumeralV1(String s) {
return s.matches("^(?=.)M*(C[MD]|D?C{0,3})(X[CL]|L?X{0,3})(I[XV]|V?I{0,3})$");
}
// 좋은 방법
static boolean isRomanNumeralV2(String s) {
return ROMAN.matcher(s).matches();
}
}
💡불필요한 객체를 만들어내는 또 다른 예 - 오토박싱
- sumV1() 메서드를 보면 sum의 타입이 Long입니다. 반복문을 수행하면서 sum에 1씩 더하고 있으며 여기서 문제는 i의 타입에 있습니다. sum의 타입은 래퍼클래스인 Long이며, i는 기본 타입인 long입니다.
- 이말은 long 타입인 i는 반복문이 돌면서 sum에 더해질때마다 새로운 Long 인스턴스를 만든다는 것입니다. 결과적으로 박싱된 기본 타입보다는 기본 타입을 사용하고, 의도치 않은 오토박싱이 숨어들지 않도록 주의해야 합니다.
public class AutoBoxing {
// bad
public static long sumV1() {
Long sum = 0L;
for (long i = 0; i < Integer.MAX_VALUE; i++) {
sum += i;
}
return sum;
}
// good
public static long sumV2() {
long sum = 0L;
for (long i = 0; i < Integer.MAX_VALUE; i++) {
sum += i;
}
return sum;
}
}
💡결론
- 불필요한 객체 생성을 피하라는 말이 "객체 생성은 비싸니 피해야한다"라고 오해하면 안됩니다.
- 요즘 GC는 상당히 잘 최적화되어 있어서 가벼운 객체를 생성 및 회수하는 일은 별로 부담이 되는 작업이 아닙니다.
- 데이터베이스 연결 같은 경우 생성 비용이 워낙 비싸니 재사용하는 편이 좋습니다. 하지만 일반적으로는 자체 객체 풀은 코드를 헷갈리게 만들고 메모리 사용량을 늘리고 성능을 떨어뜨립니다.
- 무엇보다 이렇게 객체를 방어적으로 복사하는 방식은 피해가 발생했을 때 객체를 반복 생성했을 때보다 훨씬 큽니다. 반복 생성의 부작용은 코드 형태나 성능에만 영향을 주지만, 방어적 복사가 실패한 경우에는 버그와 보안 문제로 직결됩니다.
728x90
반응형
'스터디 > 이펙티브 자바' 카테고리의 다른 글
이펙티브 자바 - Item8. finalizer와 cleaner 사용을 피하라. (0) | 2022.07.03 |
---|---|
이펙티브 자바 - Item7. 다 쓴 객체 참조를 해제하라. (0) | 2022.07.03 |
이펙티브 자바 - Item5. 자원을 직접 명시하지 말고 의존 객체 주입을 사용하라. (0) | 2022.07.02 |
이펙티브 자바 - Item4. 인스턴스화를 막으려거든 private 생성자를 사용하라. (0) | 2022.07.02 |
이펙티브 자바 - Item2. 생성자에 매개변수가 많다면 빌더를 고려하라. (0) | 2022.07.02 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
TAG
- 레이어드 아키텍처란
- spring boot 엑셀 다운로드
- java userThread와 DaemonThread
- pipe and filter architecture
- java ThreadLocal
- redis 대기열 구현
- transactional outbox pattern
- transactional outbox pattern spring boot
- redis sorted set
- 트랜잭셔널 아웃박스 패턴 스프링부트
- JDK Dynamic Proxy와 CGLIB의 차이
- space based architecture
- polling publisher spring boot
- 트랜잭셔널 아웃박스 패턴 스프링 부트 예제
- redis sorted set으로 대기열 구현
- 자바 백엔드 개발자 추천 도서
- spring boot poi excel download
- 서비스 기반 아키텍처
- 람다 표현식
- spring boot redis 대기열 구현
- spring boot redisson destributed lock
- spring boot excel download oom
- service based architecture
- microkernel architecture
- pipeline architecture
- 공간 기반 아키텍처
- spring boot redisson sorted set
- spring boot excel download paging
- @ControllerAdvice
- spring boot redisson 분산락 구현
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
글 보관함