Static Dispatch && Dynamic Dispatch
2023. 2. 16. 09:35ㆍCS
반응형
컴파일
런타임
- 런타임이란 프로그램이 실행되고 있는 동안의 동작을 의미한다.
런타임 오류
- 런타임 오류란 런타임 시 발생한 오류에 대해서 의미한다.
- 런타임 오류에 대해서 처리하도록 만든것이 예외처리이다.
let numbers = ["1", "2", "a"]
for num in numbers {
print(Int(num)!) // Thread 1: Fatal error:
}
- 강제 옵셔널 추출같은 경우에도 컴파일타임에서는 확인하지 못하고 이 코드가 실행하는 런타임에서 발생하므로 런타임 오류이다.
print(numbers[3]) // Thread 1: Fatal error: Index out of range
- 위와 같이 배열의 범위를 벗어난 Index는 접근이 불가능하기때문에 런타임시에 에러가 발생하게 됩니다.
- 위 예제들과 같이 컴파일 단계에서 확인할 수 없고, 코드가 실행되는 런타임동안 확인할 수 있는 에러를 런타임에러라고 합니다.
Dispatch
- 디스패치란, 어떤 메소드를 호출할 것인가를 결정하여 그것을 실행하는 과정
- 정적(Static)디스패치, 동적(Dynamic)디스패치가 있다.
- 정적디스패치는 컴파일 시점, 동적디스패치는 런타일 시점에서 어떤 메소드를 호출할 것인지를 결정한다.
Static Dispatch
- 컴파일 시점에서 어떤 메소드를 호출할지 결정해준다.
- 컴파일시점에서 이에 대해 결정해주므로 런타임에 비해 실행시 성능상 이점을 가질 수 있다.
- 기본적으로 값 타입에 있는 메소드들은 Static Dispatch를 사용한다.
Dynamic Dispatch
- 런타임 시점에서 어떤 메소드를 호출할지 결정해준다.
- 런타임시점에서 결정하기 때문에 컴파일 타임에 비해 실행시 성능이 좋지 않다.
왜 Static Dispatch에 비해 느린 Dynamic Dispatch를 사용하는 걸까?
class School {
func eatLunch() {
}
}
class HighSchool: School {
override func eatLunch() {
super.eatLunch()
}
}
class ElementSchool: School {
override func eatLunch() {
super.eatLunch()
}
}
- 위
eatLunch
메소드를 사용한다면 이는School
,HighSchool
,ElementSchool
의 어떤 타입의eatLunch
메소드를 사용하는지에 대하여 해당 메소드를 저장해두었다가 해당 메소드를 부르고 타입을 확인하는 과정을 거쳐야한다. - 그러나, 상속가능한 객체는 메모리에 런타임에 할당되므로 런타임 시점에서만 확인할 수 있다.
- 그러므로 위와 같이
override
가능한 메소드의 경우 정확한 타입을 확인하기 위해 Dynamic Dispatch를 사용하게 된다.
어떤 타입인지 어떻게 구별하는 걸까?
let busanHighSchool = HighSchool()
let koreaElementSchool = ElementSchool()
busanHighSchool.eatLunch()
koreaElementSchool.eatLunch()
- 위 코드를 통해 HighSchool타입의 인스턴스
eatLunch
와 ElementSchool타입의 인스턴스eatLunch
를 사용한다는 것은 알 수 있다. - 다만, 컴파일타임에서는 인스턴스가 아직 메모리에 할당되지 않았으므로 어떤 하위 클래스의 인스턴스인지 알 수 없으므로 런타임 시점에 실행되게 된다.
- Dispatch는 각각의 메소드에 포인터를 가지고 있다. 클래스 인스턴스는 각각 메소드에 대한 주소값을 가지고 있으며 VTable에 해당 메소드를 찾아 실행을 한다.
V-Table(Virtual Method Table)
- 클래스에 메소드를 정의할 때 마다 컴파일러는 해당 타입에 대하여 메소드 주소를 추가합니다.
- 위에서 설명한 것처럼 컴파일 시점에서 VTable에 해당 클래스에 대한 메소드 주소를 추가한다.
- 이후 런타임시점에서 해당 인스턴스가 메모리에 할당이 된다.
- 각각 인스턴스의 메소드가 호출을 한다면 VTable에 저장된 주소 값을 참조하여 해당 코드를 실행한다.
- 위 사진은 VTable이 각각 나뉘어져있지만 실제로는 각각 상속된 타입이므로 해당 타입을 알아내기 위해서는 모든 테이블을 확인하여 맞는 타입에 대한 메소드를 결정한다.
- 그렇기 때문에 그만큼의 비용이 증가하여 오버헤드가 발생하게 된다.
정리
- 컴파일 시점인지, 런타임 시점인지에 따라서 Static Dispatch와 Dynamic Dispatch가 나뉘게 된다.
- Static Dispatch는 컴파일 시점에서 어떤 메소드를 호출할지 결정되므로 실행속도가 Dynamic Dispatch에 비해 빠르다
- 다만 객체지향의 특징 중 하나인
다형성
으로 인해 비교적 속도가 느린 Dynamic Dispatch를 사용하게 된다.
참고자료
반응형