일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- Hashing
- hstack
- Test
- 생각
- 더채플엣청담
- JavaScript
- SWIFT
- Universal Hashing
- AlignmentGuide
- Linked List
- 각도
- enum
- 결혼식장계약후기
- 다짐
- Double Linked List
- layout
- stack
- Optional
- 베뉴
- 자료구조
- optional binding
- 레이아웃
- 좌표공간
- Optional Chaining
- vstack
- 시계방향
- nodejs
- swiftUI
- Today
- Total
klioop for iOS
Static, Dynamic(table), 그리고 Message dispatch 본문
우선 제 글보다 제가 참고한 자료들 보고 공부하시는게 훨씬 유용할 것 같으니 참고한 자료 링크부터 공유하겠습니다.
https://www.youtube.com/watch?v=Qbam_n4-ebg
https://www.rightpoint.com/rplabs/switch-method-dispatch-table
Method Dispatch 가 뭔가요
먼저 method dispatch 가 무엇인지 알아야 하겠습니다.
method dispatch 는 모든 컴파일 프로그램 언어에 적용되는 개념입니다.
dispatch 의 동의어 중 하나는 send 입니다. '보내다' 라는 의미처럼 method dispatch 는
앱에게 실행할 method 가 메모리 어디 위치에 있는지를 알려주기 위해 존재합니다.
제가 참고한 글에서는 다음과 같이 정의하고 있습니다.
Method Dispatch is how a program selects which instructions to execute when invoking a method.
한 앱에서 어떤 메소드가 호출될 때 앱이 해당 메소드를 실행할 방법을 선택하는 것으로 이해하면 될까요
개발자가 매번 신경쓰지 않아도 메소드가 실행될 때 마다 method dispatch 도 항상 함께 선택됩니다.
method dispatch 종류는 direct(static), dynamic(table), 그리고 message dispatch 이렇게 세 가지 존재하고 swift 에서는 세 가지 모두를 사용합니다. swift 는 이 세 가지 dispatch 를 상황에 맞게 스스로 잘 사용한다고 해요.
하지만 성능이 중요한 코드를 작성할 때 개발자가 dispatch 를 이해하고 swift 컴파일러에게 어떤 dispatch 를 선택할 지 직접 잘 알려줄 수 있습니다.
Static Dispatch
Direct 또는 Static Dispatch 는 세 가지 dispatch 중 에 가장 빠른 dispatch 입니다.
컴파일러는 이미 실행할 메소드의 위치를 알고 있습니다. 그래서 메소드가 호출되면 바로 컴파일 타임에서 실행할 수 있습니다.
static dispatch 는 빠르지만 정적입니다. 메소드가 변하는 환경에서는 사용할 수 없어요.
예를 들면, 클래스를 상속 받아서 메소드를 override 해야 할 때는 static dispatch 는 사용될 수 없습니다.
Dynamic(Table) Dispatch
클래스와 같은 참조형 타입들을 다룰 때, Swift 컴파일러는 관련된 메소드의 포인터들을 저장하고 있는 배열을 가집니다.
Swift 환경에서 이 배열은 witness table 이라고 불리는데요. 다른 언어에서는 virtual table 로 불린다고 합니다.
상속의 경우
하위 클래스가 생길 때마다 하위 클래스를 위한 witness table 도 부모 table 을 복사해서 만들어 집니다.
그리고 이 하위 클래스가 메소드를 새로 만들면,
하위 클래스의 witness table 마지막에 해당 메소드의 주소, 포인터가 append 됩니다.
또는 하위 클래스가 상위 클래스 메소드를 override 하면 테이블은 해당 매소드의 새로운 주소와 함께 업데이트 됩니다.
자세한 메커니즘은 참조 자료 중 두 번째 자료를 보시고 여기서는 간단하게만 다루겠습니다.
컴파일러는 table dispatch 로 메소드를 실행할 때 witness 테이블에서 항상 메소드의 위치를 찾아야 합니다.
이 때 witness table 의 참조는 runtime 에서 일어납니다.
메소드가 override 되어 있는지 확인해야 하기 때문입니다.
위 사진의 자식 클래스의 method2 가 override 되어있고 실행되었다면,
컴파일러는 자식 클래스의 witness table(vTable) 로 가서 해당 메소드의 주소를 찾습니다.
method2 가 override 되어있으니 0x222 주소로 가겠지만, 만약 override 되어있지 않다면 0x122 로 가겠죠.
그래서 static dispatch 로 메소드를 실행할 때 보다 속도가 느립니다.
하지만 상속을 가능하게 하고 메소드의 행위를 바꾸게 해주는 측면에서 static dispatch 보다 유연합니다.
Message Dispatch
Message Dispatch 는 Table Dispatch 보다 더 유연한데요.
message dispatch 는 runtime 에서 dispatch 의 행동(메소드의 행동?)을 바꿀 수 있다고 합니다.
심지어 객체 자체도 바꿀 수 있다는데.. ;
사실 이 의미가 무엇인지는 이해 하지 못했습니다.
Method Swizzling 이 항상 message dispatch 에서만 가능하다고 하는데 다음에 공부하면서 살펴봐야겠습니다.
Cocoa 에서 핵심인 KVO 와 Core Data 모두 message dispatch 위에서 동작한다고 합니다.
UIAppearance 도 message dispatch 로 동작한다네요.
Swift 에서 obj-c 와 관련된 메소드나 프로퍼티는 모두 message dispatch 로 실행됩니다.
따라서 dynamic 키워드가 붙은 메소드는 모두 message dispatch 로 실행된다고 생각하면 됩니다.
프로그램이 런타임에서 message dispatch 로 메소드를 실행하려면 해당 메소드를 찾기 위해 관련된 모든 참조 타입을 crawl ? 하면서
찾아야 해서 속도가 느리다고 합니다.
하지만 캐시 레이어가 관여해서 한 번 찾고나면 table dispatch 와 속도가 비슷하다고 합니다.
정리
종류 | 속도 | 유연함 |
Static(Direct) Dispatch | 가장 빠름 | 가장 없음 - 상속 제한함 |
Table(Dynamic) Dispatch | Static 보다 느리지만 Message 보다 빠름 | 상속을 가능하게 함, 런타임에서 실행할 메소드 결정할 수 있게함 - OOP |
Message Dispatch | 가장 느림 | 가장 유연함 - e.g. Method Swizzling |
Swift 환경에서 Dispatch 선택되는 케이스
소돌님 블로그에 케이스별로 코드와 함께 정리가 아주 잘 되어 있습니다.
링크 공유할 테니 자세한 케이스를 가서 확인하시면 좋을 것 같아요.
https://babbab2.tistory.com/144
저는 간단하게 요약만 할게요.
class 에서 extension 하면 왜 static dispatch 가 적용 되는지 의아했는데
extension 에서 선언한 메소드 들은 @objc 마크가 안되어있으면 하위 클래스에서 override 되지 못한다는 사실을 이번에 알았습니다.
그렇다면 메소드가 변하지 않으니 swift 컴파일러가 static dispatch 로 해당 메소드를 실행할 수 있구요.
'swift' 카테고리의 다른 글
[Swift] Optional 이해하기 (0) | 2021.06.09 |
---|---|
ARC, weak, and weak self (0) | 2021.03.17 |
value type vs reference type (0) | 2021.03.17 |