# ITEM6 불필요한 객체 생성을 피하라
객체 하나를 재사용하는 예시에는 불변 객체가 적합하다.
불변 객체는 재사용해도 안전함이 명백함.
# primitive 문자열, Object 문자열
String s = new String("bikini");
- new → Heap 영역
- 문장 실행마다 String 인스턴스를 새로 생성.
- 반복과 호출이 많아지면 String 인스턴스가 메모리를 차지함.
String s = "bikini";
- 리터럴 → string constant pool 영역
- 내부적으로 String 의 intern() 메서드가 호출
- intern() 메서드는 문자열이 string constant pool 에 존재하는지 검색
- 있다면 그 주소값을 반환
- 없다면 string constant pool 에 넣고 새로운 주소값을 반환
- intern() 메서드는 문자열이 string constant pool 에 존재하는지 검색
- 하나의 String 인스턴스 사용
- 같은 가상 머신 안에서, 똑같은 문자열 리터럴을 사용하는 모든 코드가 같은 객체를 사용함을 보장.
public final class String {
public native String intern();
}
1
2
3
2
3
public class Main {
public static void main(String[] args) {
String id = "taehongkim";
String id2 = new String("taehongkim");
String id3 = "taehongkim";
System.out.println(id.equals(id2)); // true 값 비교
System.out.println(id == id2); // false 주소 비교
System.out.println(id == id3); // true
}
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
- Boolean(String) 생성자 < Boolean.valueOf(String) 팩터리 메서드 [1]
# 생성비용이 비싼 객체 → 캐싱
String.matches
- 정규 표현식으로 문자열 형태를 확인하는 가장 쉬운 방법
static boolean isRomanNumeral(String s) {
return s.matches("reg");
}
1
2
3
2
3
- 내부적으로 Pattern 인스턴스 생성
- 한번쓰면 가비지 컬렉션의 대상
- 생성 비용이 높음
- Pattern 인스턴스를 캐싱 (개선후 6배 향상)
public class RomanNumerals {
private static final Pattern ROMAN = Pattern.compile(
"^(?=....)" // 정규표현식
);
static boolean isRomanNumerals(String s) {
return ROMAN.macher(s).matches();
}
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
# 지연초기화 Lazy Initialization
메서드가 처음 호출될 때 필드를 초기화 하는 것.
- 장점: 불필요한 초기화를 없앰
- 단점: 코드가 복잡해지는 만큼 성능이 크게 개선되지 않는 경우가 많음
# Auto boxing
기본타입과 박싱된 기본 타입을 섞어 쓸 때 자동으로 상호 변환해 주는 기술
오토박싱이 일어날 때 인스턴스가 생성됨 → 반복이 많이 일어나면, 성능에 좋지 않다.
sum 변수를 long 이 아닌 Long 으로 선언하였다
- Long 인스턴스가 231 개가 생성됨
- long 을 쓸 때 0.59 초 보다 Long 6.3 초로 확연히 차이가 난다.
private static long sum() {
Long sum = 0L;
for(long i = 0; i <= Integer.MAX_VALUE; i++)
sum += i;
return sum;
}
1
2
3
4
5
6
2
3
4
5
6
# 객체 풀
- 단순히 객체 생성을 피하기 위한 객체 풀 생성 X
- 일반적으로 코드가 어려워짐, 메모리 사용량을 늘리고 성능을 저하
- 데이터 베이스 연결은 생성 비용이 비쌈 → 풀 생성 O
# 타협점
- JVM 은 별다른 일을 하지 않는 작은 객체를 생성하고 회수하는 일이 크게 부담되지 않음
- 프로그램의 명확성, 간결성, 기능을 위해서 객체를 추가로 생성하는 것이라면 일반적으로 좋은 일
- [50] 새로운 객체를 만들어야 한다면 기존 객체를 재사용 하지마라
- 재사용 했을 때의 피해 → 버그와 보안구멍
- 불필요한 객체 생성 → 코드 형태와 성능에만 영향
- 객체 특성에 맞게 사용