[Swift] Method Dispatch 3편 - Dynamic Dispatch에 대한 성능 향상

어흥·2024년 6월 18일

Swift

목록 보기
26/28

Method Dispatch 1편에서 Dynamic Dispatch에 대한 내용 기억 안나시면 1편을 다시 보고 오길 바란다.

Static Dispatch와 Dynamic Dispatch 비교

Reference type 인스턴스가 메서드를 호출할 때 Table을 활용하여 Dynamic Dispatch 방식으로 이루어진다. 하지만 Direct(Static) Dispatch와 비교하면 절차가 2개가 많고 느리다는 단점이 있다.

static dispatch 과정과 dynamic dispatch 과정을 한번 비교해보자.

static dispatch

컴파일 시점에 메서드가 실행할 코드 주소를 삽입하므로 그냥 그 주소로 점프하여 코드를 실행한다.

그에 반해 dynamic dispatch 과정은 어떨까?

dynamic dispatch 과정

  1. 스택 영역에 주소 값을 담은 인스턴스 방문
  2. 주소 참조하여 힙 영역을 방문
  3. 데이터 영역에 있는 메서드 테이블 방문
    1. childObject가 0xB00에 있다고 가정하면 childObject의 디스패치 테이블을 읽는다.

    2. 메서드의 인덱스를 읽는다.

      이 경우, method2의 메서드 인덱스가 1이라고 한다면 0xB00 + 1 주소를 읽는다.

  4. 코드 영역에 있는 함수 주소로 점프하여 코드 실행

일반적인 경우에는 Dynamic Dispatch가 다형성을 만족한다는 점에서 편리하다. 하지만 static dispatch에 비해 절차가 많아 오버헤드가 발생하여 성능이 저하될 수 있습니다. 또한 Dynamic Dispatch의 가능성이 있는 코드에서는 컴파일러의 최적화를 진행할 수 없습니다.

이때, Dynamic Dispath가 필요하지 않을 경우에 사용할 수 있는 3가지의 성능 최적화 방법이 있다.

Dynamic Dispatch에 대한 성능 최적화 방법

1. final 키워드 붙여라

final 키워드는 선언된 클래스, 메소드, 프로퍼티는 오버라이드 할 수 없다. 따라서 재정의 될 필요가 없는 요소에 final을 붙이면 컴파일러는 Dynamic Dispatch를 사용하지 않아도 되므로 이 부분에 대해서 최적화가 가능하다.

2. private 키워드를 붙여라

private 키워드는 선언된 클래스, 메서드, 프로터티에 대해서 한 파일 내에서만 참조할 수 있다. 따라서 한 파일 내에 해당 요소에 대한 재정의(오버라이드)가 없는 경우 컴파일러가 dispatch 방식을 direct call로 바꿔줄 수 있어 최적화가 가능하다.

3. WMO(Whole Module Optimization) 사용하면 성능 최적화할 여지가 있다.

  • 원래 컴파일 시에 각각 파일 단위로 컴파일을 한다. 그런데 WMO를 적용하면 하나의 전체 프로젝트를 하나로 인식해서 컴파일한다.

    WMO를 적용하면 모듈 내에 오버라이드가 없다면 internal 선언만으로 final을 추론이 가능하다.

swift는 기본적으로 모듈을 이루는 파일들을 개별적으로 컴파일 하기 때문에 다른 파일에서 오버라이딩이 일어났는지 알 수 없지만 WMO를 활성화 하면 모듈 전체가 하나의 덩어리로 취급되어 컴파일 되기 때문에 이를 확인하고 더 강력한 추론이 가능하다. 이렇게 하면 internal 선언은 모듈 바깥에 드러나지 않아 오버라이딩이 불가능 하다는 것이 보장되기 때문이다.

Reference.

Method Dispatch in Swift, and its effect on performance

0개의 댓글