일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 | 31 |
- Tuist
- xcode 공백 표시
- Cocoa Pod
- 메모이제이션
- JPEG
- 타뷸레이션
- SwiftUI
- contentalignmentpoint
- nidthirdpartylogin
- 무한스크롤
- .pbxproj
- NVME
- Firestore
- fetchdescriptor
- 팀 개발을 위한 git
- TestFlight
- 코드스쿼드
- png
- 캐러셀
- JPG
- xcode 엔터 표시
- 함께자라기
- heic
- swift 모듈화
- swiftdata
- webp
- 테스트 타겟
- github 시작하기
- 클린 아키텍처
- spm 에러
- Today
- Total
Sure, Why not?
final하면 왜 좋을까? 본문
왜 좋은지 알아보자!! :)
CFAbsoluteTimeGetCurrent : 현재 절대 시간을 반환합니다.
측정하기 위한 시작 지점과 종료 지점에 생성하여, ‘종료 지점 - 시작 지점’을 연산하면 연산 시간을 대략 파악이 가능합니다.
들어가기 앞서
Instruments의 Time Profiler를 사용하여 final 유무차이에 따른 클래스의 메소드 시간을 비교하고자 하였습니다.
동일한 메소드를 호출할 때
- final 없는 클래스는 0.310초,
- final 있는 클래스는 0.304초 차이가 있습니다.
먼저 동일한 메소드를 가지고 있으며, final 유무차이만 있는 클래스를 만들었습니다.
import Foundation
class MyClass {
func doSomething() {
var uuids: [String] = []
(0..<1_000_000).forEach { _ in
uuids.append(UUID().uuidString)
}
print("MyClass: \\(uuids.count)")
}
}
final class MyFinalClass {
func doSomething() {
var uuids: [String] = []
(0..<1_000_000).forEach { _ in
uuids.append(UUID().uuidString)
}
print("MyFinalClass: \\(uuids.count)")
}
}
func measureTime(for task: () -> Void) -> Double {
let startTime = CFAbsoluteTimeGetCurrent()
task()
let timeElapsed = CFAbsoluteTimeGetCurrent() - startTime
return Double(timeElapsed)
}
let myClass = MyClass()
let myFinalClass = MyFinalClass()
let nonFinalClass = measureTime {
myClass.doSomething()
}
let finalClass = measureTime {
myFinalClass.doSomething()
}
print("MyClass time: \\(nonFinalClass)")
print("MyFinalClass time: \\(finalClass)")
// MyClass: 1000000
// MyFinalClass: 1000000
// MyClass time: 0.5914549827575684
// MyFinalClass time: 0.5820909738540649
🤔final키워드를 사용하면 왜 성능이 향상되는 걸까?
먼저 final을 문법적으로 바라보면,
- 더 이상 클래스가 상속이 필요없음을 명시할 수 있습니다.
- 서브클래스에서 특정 method, property, subscript가 오버라이드 되지 않도록 방지합니다.
- 오버라이드 하면, 컴파일타임에서 에러 발생합니다.
성능적으로 바라보기 위해서, 2가지 방식을 알아야 합니다.
Dynamic Dispatch는 런타임에 호출할 메서드를 결정하는 방식입니다.
클래스마다 가상테이블(vtable)을 가지고 있으며, 함수 포인터를 지정합니다. 이를 참조해서 실제 함수를 호출하는 과정을 거치게 됩니다.
그래서 정리하면 vtable은 클래스가 어떠한 함수를 호출해야하는지 결정하는 테이블을 가지고 있는 것입니다.
이러한 과정들이 약간의 오버헤드를 발생하여 성능적으로 불리할 수 밖에 없습니다.
반면에,
Static Dispatch는 컴파일 타임에 호출할 메서드를 결정하는 방식입니다.
동적 디스패치처럼 조회 단계가 없기 때문에,
메서드가 오버라이드될 수 없음을 보장하여 메서드 호출이 빠른 것입니다.
그래서 final을 사용하게 되면 Static Dispatch 메커니즘을 사용하여 위의 결과처럼 실제 오버헤드의 차이를 확인할 수 있었던 것입니다.
😎정리
실제 final키워드를 사용유무에 따라 시간 결과를 두눈으로 확인하면서 final키워드의 필요성을 알게되었습니다.
클래스 객체를 만들 때, 설계를 고려하면서 final 키워드를 사용하는 것이 얼마나 중요한지 이해할 수 있었습니다.
📄Reference
'💻' 카테고리의 다른 글
PNG와 JPEG의 차이 (2) | 2024.09.05 |
---|---|
Memory Leak 메모리 누수 (0) | 2024.09.02 |
Virtual Memory 가상 메모리 (2) | 2024.09.01 |
List 데이터 식별하는 방법 (0) | 2024.08.31 |
Split과 Components 차이 (0) | 2024.08.30 |