7장. 비용 줄이기
아이템 45. 불필요한 객체 생성을 피하라
- 객체를 Wrap 하게 되면 3가지 비용이 발생한다.
- 헤더 및 레퍼런스를 위한 추가 공간
- 요소가 캡슐화 되어있다면, 접근을 위한 함수 호출 비용
- 객체 생성을 위한 메모리 공간 할당 및 레퍼런스 생성 비용
- 캐싱 기법을 활용해서 객체를 재활용하면 불필요한 객체 생성으로 인한 비용을 줄일 수 있다.
- 단, 캐시는 언제나 메모리와 성능의 트레이드 오프가 발생하기 때문에 여러가지 상황을 잘 고려해서 사용해야한다.
- 무거운 클래스를 생성할 때 지연 초기화를 하는 것이 좋을 수 있다.
- 하지만, 백엔드 애플리케이션과 같은 특수한 경우에는 지연초기화를 통해 첫번째 응답시간이 굉장히 길어지는 문제와 성능 테스트가 복잡해지는 단점을 가지고 있다.
아이템 46. 함수 타입 파라미터를 갖는 함수에 inline 한정자를 붙여라
inline
한정자의 역할은 컴파일 시점에 함수를 호출하는 부분을 함수의 본문으로 대체하는 것이다.
- 일반적인 함수를 호출하면 함수 본문으로 점프하고 본문의 모든 문장을 호출한 다음, 함수를 호출했던 위치로 다시 점프하는 과정을 거친다.
inline
한정자를 사용하면 이러한 점프가 일어나지 않는다.
inline
한정자를 사용하면 다음과 같은 장점을 얻을 수 있다.
- 타입 아규먼트에
reified
한정자를 붙여서 사용할 수 있다.
- 함수 타입 파라미터를 가진 함수가 훨씬 더 빠르게 동작한다.
- 비지역 리턴을 사용할 수 있다.
inline
한정자는 모든 곳에서 사용할 수 없다.
- 재귀적으로 사용할 경우 무한하게 대체되는 문제가 발생한다.
- 가시성 제한을 가진 요소를 사용할 수 없다.
inline
한정자를 남용하면 코드의 크기가 쉽게 커진다.
crossinline
: 아규먼트로 인라인 함수를 받지만 비지역적 리턴을 하는 함수는 받을 수 없게 만든다.
- 인라인으로 만들지 않은 다른 람다 표현식과 조합해서 사용할 때 문제가 발생하는 경우에서 활용한다.
noninline
: 아규먼트로 인라인 함수를 받을 수 없게 만든다, 인라인 함수가 아닌 함수를 아규먼트로 사용하고 싶을 때 활용한다.
아이템 47. 인라인 클래스의 사용을 고려하라
- 프로퍼티가 단 하나만 존재하는 클래스는
inline
한정자를 붙여서 inline
클래스로 만들 수 있다.
inline
클래스는 해당 객체를 사용하는 위치가 모두 해당 프로퍼티로 교체된다.
inline
클래스의 메서드는 모두 정적 메서드로 만들어진다.
inline
클래스는 다른 자료형을 Wrapping해서 새로운 자료형을 만들 때 많이 사용된다.
inline
클래스도 인터페이스를 구현할 수 있지만, 인터페이스를 구현하는 inline
클래스는 inline
으로 동작하지 않는다.
- 인터페이스를 통해서 타입을 나타내려면, 객체를 Wrapping해서 사용해야하기 때문에 인터페이스를 구현하는
inline
클래스는 아무런 의미가 없다.
typealias
를 이용해서 타입에 새로운 이름을 붙여줄 수 있으며, 이는 길고 반복적으로 사용해야할 때 유용하다.
typealias
는 단순하지만 안전하지 않으며, 이를 잘못 사용한 경우에도 어떠한 요류가 발생하지 않기 때문에 문제를 찾는 것을 더 어렵게 만든다.
- 때문에 비용과 안전이라는 두 가지 측면을 위해서는
inline
클래스를 사용하자.
아이템 48. 더 이상 사용하지 않는 객체의 레퍼런스를 제거하라
- 가비지 컬렉터를 맹신하고 메모리 관리를 완전히 무시해버리면, 메모리 누수가 발생하여 최악의 경우 OOME가 발생할 수 있다.
- 때문에 더 이상 사용하지 않는 개체의 레퍼런스는 유지하면 안된다라는 규칙 정도는 지켜주는 것이 좋다.
- 객체에 대한 참조를
companion
또는 static
으로 유지해버리면, 가비지 컬렉터가 해당 객체에 대한 메모리 해제를 할 수 없다.
- 특히, Activity와 같은 큰 객체를 이렇게 선언할 경우 메모리를 해제할 수 없어 굉장히 큰 메모리 누수가 발생하게 된다.
- 때문에 비용이 큰 객체는 리소스를 정적으로 유지하지 않는 것이 가장 좋다.
- 범용적으로 사용하는 라이브러리는 어떻게 사용될지 예측하기 어렵기 때문에 최적화에 신경을 더 써야한다.
- 때문에 사용하지 않는 오브젝트에 명시적으로
null
을 할당하여 초기화하자.