어떤 코드를 사용할지 성능을 고려했을 때 보다 관용적인 솔루션을 찾을 수 있음
=> "성능"에 초점을 맞추자
- Allocation - Stack vs Heap
- Reference Counting - Less vs More
- Method Dispatch - Static vs Dynamic
Swift는 자동적으로 메모리를 할당/해제
구조체 선언
-> Stack에 할당 = 실제 값을 저장
- 다른 인스턴스로 복사
-> Stack에 복사한 값을 할당
-> 원본을 변경해도 복사한 값엔 영향 없음
-> 모두 사용하고 나면 스택 포인트를 다시 올려서 간단하게 해제
클래스 선언
-> Stack에 메모리 할당 = 힙에 할당한 참조 값을 저장
- 다른 인스턴스에 전달 시 참조를 복사
-> 원본을 변경 시 그대로 변경된 값이 공유됨
-> 모두 사용 시 Swift가 메모리를 할당 해제하며 블록 위치 조정
-> Stack을 해제
➡️ Class는 Heap 할당이 필요하기 때문에 Struct보다 비용이 많이 든다
➡️ Class의 특성이 필요하지 않다면 Struct를 사용하는 것이 좋다 ❕
String은 구조체니까 Stack 영역만 사용?
No => String도 간접적으로 힙을 사용
ex) key로 String을 사용하는 경우 대신 새로운 Struct 타입을 정의해 사용
🤔 Swift는 Heap에 할당한 메모리를 언제 해제할까?
=> Heap 인스턴스에 대한 참조 수를 세고 있음
❗️ 중요한 것은 이 작업이 매우 빈번하며 많은 비용이 필요
Struct는 참조 카운트를 가지지 않음
하지만 반드시 그런 것은 아님!
String은 내용을 Heap에 저장 = 참조 카운트 필요
참조가 포함된 Struct라면 역시 참조 카운팅에 대한 오버헤드 발생
ex) Struct 내부에 둘 이상의 참조를 가진 경우 클래스보다 더 많은 오버헤드 유지
이런 식으로 참조가 필요한 타입의 사용을 자제하기
클래스는 기본적으로 메서드를 동적으로 전달
-> final
표현을 통해 하위 클래스가 없음을 전달할 수 있음
= 컴파일러가 해당 메서드를 정적으로 디스패치
이외에도 클래스를 서브클래싱하지 않음을 추론할 수 있는 경우 정적 디스패치로 전환
구조체를 사용해 다형성 코드를 작성하는 방법 => POP
V-Table
디스패치를 수행하는 상속 관계를 공유하지 않음V-Table
과 비슷한 매커니즘word
: 프로퍼티 하나의 단위Value Buffer
: 값을 저장하는 공간Buffer(3) + VWT + PWT
Value Buffer
에 저장프로토콜을 채택하고 규모가 넘 커서
Value Buffer
에 담기지 않으면 힙 영역을 사용하게 된다
힙을 사용하는 것과 아닌 것을 어떻게 구분하여 관리?
=> Value Witness Table
allacate : 할당
copy : 실제로 값을 가져옴
destruct : RC을 관리
deallocate : 할당 해제
"프로토콜을 사용하면 구조체라도 여전히 다이나믹 디스패치를 사용할 수도 있구나..!"
-> 그럼에도 클래스보다는 비용이 저렴
큰 구조체인 경우 복사 시 계속 힙 할당이 아니라 Value Buffer가 같은 참조값을 가지게 됨
=> 그럼 클래스처럼 공유 문제가 발생하나?
값을 무조건 복사하지 않고 주소만 참조하고 있다가 값이 변경되면 복사
구조체를 사용하더라도 RC를 사용할 수 있다
구조체가 크다 -> 힙을 사용 (CoW로 문제 해결)
구조체에 참조가 포함되어 있다 -> RC 사용
PWT -> 동적 디스패치로 동작
제네릭과 프로토콜의 차이점 = 제네릭은 Parametric Polymorphism 라고 하는 정적인 형태의 다형성 지원
Swift는 제네릭 타입 T를 호출에서 사용하는 타입으로 바인딩
내부 작업을 수행하기 위해 프로토콜 및 VWT 사용
호출 컨텍스트당 하나의 타입이기 때문에 Existential Container는 사용하지 않음
-> 대신 스택에 valueBuffer를 할당
Static polymorphism
정적 디스패치로 사용할 수 있음
코드상에서 타입을 직접적으로 주입하니까 동적으로 알아낼 필요가 없다
동적 런타임 요구 사항이 가장 적은 추상화를 선택하기
프로토콜 또는 제네릭에서 큰 값을 사용할 때 Heap을 사용 -> CoW로 해결