[Effective Java] 아이템 67 : 최적화는 신중히 하라

Loopy·2022년 12월 3일
0

이펙티브 자바

목록 보기
65/76
post-thumbnail

최적화는 섣불리 진행하면 좋은 결과보다 해로운 결과로 이어지기 쉽다.
따라서, 프로그램이 우선 좋은 아키텍처를 가질 수 있도록 한 이후에나 최적화를 고려해야 한다.

☁️ 좋은 설계

성능을 제한하는 설계를 피하라

구현상의 문제가 아닌 아키텍처 결함이 성능을 제한하는 상황이라면, 완성된 기본 틀을 변경해야 하기 때문에 유지보수나 개선하기 어려운 시스템이 만들어진다. 따라서, 성능을 염두해두고 설계하도록 하자.

API 설계 시 성능에 주는 영향을 고려하라

  1. public 타입을 가변으로 만들어 내부 데이터를 변경할 수 있게 만드는 것은, 불필요한 방어적 복사를 유발한다.

  2. 컴포지션으로 해결할 수 있음에도 상속 방식으로 설계한 public 클래스는 상위 클래스에 영원히 종속되며 그 성능 제약까지도 물려받게 된다.

  3. 인터페이스가 있는데 구현 타입을 사용하는 것은 특정 구현체에 종속되게 하여, 나중에 더 빠른 구현체가 나오더라도 이용하지 못하게 된다.

1번의 대표적인 예시로 java.awt.Component 클래스의 getSize 메서드가 있다.

public abstract class Component implements ImageObserver, MenuContainer,
                                           Serializable
{
    public Dimension getSize() {
        return size();
    }

    @Deprecated
    public Dimension size() {
        return new Dimension(width, height); // 방어적 복사 수행 
    }
}

아래와 같이 Dimension을 가변으로 설계했기 때문에 getSize를 호출하는 모든 곳에서 Dimension 인스턴스를 새로 생성하고 있다. 요즘의 VM이라면 작은 객체를 몇 개 생성하는게 큰 부담은 아니지만, 수백만 개를 생성해야 한다면 성능에 영향을 줄 수도 있기 때문이다.

public class Dimension extends Dimension2D
		implements java.io.Serializable {  // 불변이 아니다

    public int width;
    public int height;

    public void setSize(int width, int height) {
          this.width = width;
          this.height = height;
    }
}

☁️ 성능 측정

jmh 같은 프로파일링 도구는 최적화 노력을 어디에 집중해야 할지 찾는데 도움을 준다.

가장 먼저 살펴볼것은, 개별 메서드의 소비 시간과 호출 횟수 같은 런타임 정보의 제공을 이용해서 알고리즘을 알맞게 골랐는지 확인하는 것이다. 알고리즘을 잘못 골랐다면 다른 저수준 최적화는 아무런 소용이 없어진다.

참고로 자바는 C/C++보다 성능 모델이 덜 정교하다. 프로그래머가 작성하는 코드와 CPU에서 수행하는 명령 사이의 '추상화 격차'가 크기 때문에 최적화로 인한 성능 변화를 일정하게 예측하기가 어렵기 때문이다.

📚 핵심 정리
좋은 프로그램을 작성하다 보면 성능은 따라오므로 빠른 프로그램을 작성하려 안달하지 않아도 된다. 특히 API, 네트워크 프로토콜, 영구 저장용 데이터 포맷을 설계할 때는 성능을 염두해 두어야 한다. 시스템 구현을 다했다면 성능을 측정해보고 충분히 빠르지 않다면 프로파일러를 사용해 문제의 원인이 되는 지점을 찾아 최적화를 수행하자. 만족할 때까지 반복하고, 모든 변경 후에는 성능을 측정하라.

profile
개인용으로 공부하는 공간입니다. 잘못된 부분은 피드백 부탁드립니다!

0개의 댓글