안녕하세요 🐶
빈 지식 채우기의 비니🙋🏻♂️ 입니다.
오늘은 COW ( Copy-On-Write )에 대해 알아보는 시간을 가지겠습니다.COW..? 음머머머머
1. 개요
Swift에서의 메모리 참조에는 크게 값 타입과 참조 타입이 있습니다.
그 중 값 타입의 경우는 새로운 인스턴스를 생성하거나 파라미터로 전달될 때 값 복사가 이루어집니다.
다만, 이러한 값 복사 작업은 시간이 상당히 걸리기 때문에 해결방안으로 나온 기술이 바로 COW ( Copy-On-Write ) 입니다.
간단히 말하면, 실제 사용할 때 복사한다! 라는 의미로 자세히 알아보도록 하겠습니다.
2. 예시
2-1. 준비
아래 소스와 같이 주소를 알 수 있는 함수를 정의한 뒤 진행한다.
UnsafeRawPointer 란 간단히 말해 객체의 메모리 주소를 나타내는 타입이다.
func printAddress(object: UnsafeRawPointer) {
print(object)
}
2-2. Array
먼저 Array를 통해 확인해 보도록 하겠습니다.
func testArray() {
let arr1 = [1, 2, 3, 4, 5] // (1)
var arr2 = arr1 // (2)
printAddress(object: arr1)
printAddress(object: arr2)
arr2[0] = 0 // (3)
printAddress(object: arr2)
}
위에 간단하게 만든 Array의 COW 테스트 소스가 있습니다
- arr1 배열 생성
- arr2에 arr1을 할당
- arr2의 첫 번째 인덱스의 값 변경
위의 결과로 알 수 있듯이 Array 의 경우 COW ( Copy-On-Write ) 가 구현이 되어 있는 것을 볼 수 있다.
왜냐하면 arr2에 arr1이 할당했을 때는 동일한 주소를 바라보고 있으나, arr2의 값이 수정되는 순간 복사가 일어나는 것을 확인할 수 있다.
2-3. Set, Dictionary
다른 Collection 타입인 Set 과 Dictionary도 확인해보겠습니다.
func testSet() {
var set1: Set<Int> = [1, 2, 3]
var set2 = set1
printAddress(object: &set1)
printAddress(object: &set2)
}
func testDictionary() {
var dic1: Dictionary<Int, Int> = [1:1, 2:2, 3:3]
var dic2 = dic1
printAddress(object: &dic1)
printAddress(object: &dic2)
}
Array와 마찬가지로 테스트를 위해 소스를 작성해보았습니다.
엥..? 왜 Array와 다르게 Set, Dictionary는 주소가 다르지.. Colletion 타입은 모두 COW가 구현되어 있다고 했는데..
좀 더 확인해본 결과 Array와 다르게 Set과 Dictionary는 Address Wrapping이 일어나는 것으로 보인다..응 니 추측이야😢
이 부분에 대해서는 좀 더 공부가 필요할 것으로 보인다.. ( 답 아시는 분은 댓글 남겨주세요 🙏🏻 )
2-4. Struct
대표적인 값 타입으로 정의되는 Sturct로 확인해보도록 하겠습니다.
struct someStruct {
var a: Int
var b: Int
}
func testStuct() {
var struct1 = someStruct(a: 1, b: 2)
var struct2 = struct1
printAddress(object: &struct1)
printAddress(object: &struct2)
struct1.a = 10
printAddress(object: &struct2)
}
동일하게 Struct도 진행하였다.
위와 같이 서로 다른 주소 공간에 값들을 가지고 있는 것이 확인되었다.
고로 Struct 구조체는 COW가 구현되어 있지 않다고 알 수 있다.
그렇다면 사용자가 직접 COW 기능을 활용하고 싶을 때는 어떻게 해야 할까?
final class Ref<T> {
var val : T
init(_ v : T) {val = v}
}
struct Box<T> {
var ref : Ref<T>
init(_ x : T) { ref = Ref(x) }
var value: T {
get { return ref.val } // (1)
set {
// 유일하게 참조되는지를 확인
if (!isUniquelyReferencedNonObjC(&ref)) { // (2)
ref = Ref(newValue) // (3)
return
}
ref.val = newValue // (4)
}
}
}
위와 같이 COW 기능을 직접 구현한 소스를 확인할 수 있다.
- Getter의 경우는 참조 데이터를 그대로 반환한다.
- Setter의 경우 해당 값이 유일하게 참조되어 있는지를 확인한다.
- 아닐 경우, 새로운 참조되는 인스턴스를 생성하여 반환한다.
- 맞는 경우, 기존 주소의 있는 값을 수정한다.
3. 결론
- Swift에서 기본적으로 COW가 구현되어 있는 타입은 Collection 프로토콜을 준수하는 Array, Dictionary, Set, String 등이 있다.
- Struct의 경우 COW 동작이 구현되어 있지 않으므로, 필요하다면 위와 같이 사용자가 직접 구현을 해줘야 한다.
이상으로 COW ( Copy-On-Write ) 포스팅을 마치겠습니다.
틀린 부분이나 궁금한 사항은 댓글 남겨주세요~🤭
참고
'iOS📱 > Swift' 카테고리의 다른 글
[ Swift ] KVC(Key-Value-Coding), KVO(Key-Value-Observing) (0) | 2023.01.05 |
---|---|
[ Swift ] 서브스크립트 ( Subscript ) (0) | 2022.12.30 |
[ Swift ] ARC (2) Retain Cycle, 강한참조, 약한참조 그리고 미소유참조 (0) | 2022.12.29 |
[ Swift ] ARC (1) 기본 개념, Reference Count 이해 (0) | 2022.12.28 |
[ Swift ] Class vs Struct (0) | 2022.12.26 |