똑같은 기능의 객체를 매번 생성하는 것은 매번 해당 객체가 GC의 대상이 되며, 객체 생성이 비용이 들게 된다. 따라서 객체 생성 비용을 줄이고, GC를 줄이기 위해 객체 하나를 재사용하자.
String s = new String("bi");//절대 하면 안됨
String s = "bi";//이런식으로해야함
String을 new로 사용하지 않고 리터럴 값으로 생성하면 상수 풀에 값이 저장되며 동일한 reference를 가져 재사용할 수 있다.
new String() 방식을 사용하게 되면 생성한 변수는 상수 풀에 저장되지 않고, Heap 메모리에 저장되어 다른 reference를 가진다.
생성자 대신에 저적 팩토리 메소드를 통해 불필요한 객체 생성을 피할 수 있다.
public static Boolean valueOf(boolean b) {
return b? Boolean.TRUE : Boolean.FALSE;
}
static boolean isRomanNumeral(String s) {
return s.matches("...");
}
위 코드는 String.matches 메서드를 사용한다. 해당 메서드는 성능이 중요한 상황에서 반복해 사용하기엔 적합하지 않다. 왜냐하면 내부에서 만드는 정규표현식용 Pattern 인스턴스가 매번 한번쓰고 버려지며 GC의 대상이 되기 때문이다.
따라서 String.matches보다는 Pattern 인스턴스를 클래스 초기화 과정에서 직접 생성해 캐싱해두고 재활용하는 것이 났다.
클래스 초기화 : JVM 클래스로더에 의해 런타임시에 클래스를 처음으로 참조할 때 로딩 -> 링킹 -> 초기화 과정을 통해 동적 로드를 한다. 이 초기화 과정에서 STATIC initializer를 수행한다.
public class Roman {
private static final Pattern ROMA = Pattern.compile("....");
static boolean isRomanNumeral(String s) {
return ROMAN.matcher(s).matches();
}
}
Set<String> s1 = hm.keySet();
Set<String> s2 = hm.keySet();
같은 인스턴스를 대변하는 여러개의 인스턴스를 생성하지 말자.
Map 인터페이스의 keySet함수는 결국 같은 Map을 대변하기 때문에 생성되는 Set 인스턴스들은 결국 동일한 Map을 대변할 뿐이다. 따라서 불필요하게 생성할 필요가 없다.
오토박싱은 기본 타입과 박싱된 기본 타입을 섞어 쓸 때 자동으로 박싱과 언박싱을 통해 타입을 상호 변환해주는 기술이다.
불필요한 박싱/언박싱은 불필요한 객체 생성을 유발한다. 박싱된 기본타입 보다는 기본타입을 사용하여 의도치않은 오토박싱이 숨어들지 않도록 해야 한다.
private static long sum() {
Long sum = 0L;
for (long i = 0; i<=Integer.MAX_VALUE; i++) {
sum += i;//long 타입인 i가 Long 타입인 sum에 더해질때마다 매번 Long 객체를 생성
}
return sum;
}
sum 변수를 Long으로 선언해서 불필욯나 Long 인스턴스가 약 2^31개나 만들어진다. long 타입인 i가 Long 타입인 sum에 더해질때마다.
이럴 경우 단순히 sum의 타입을 long 으로 바꾸면 불필요한 객체 생성을 막는다.
객체 재사용은 방어적 복사와는 대조적이다.
객체 재사용 시 피해가 큰 경우 방어적 복사 방식을 사용하여 객체를 반복해서 생성할 수도 있다. 상황에 따라 다름. (아이템 50)
이펙티브 자바