Swift

[Swift] 간단히 알아보는 Copy-on-Write

Jade-Lee 2024. 3. 19. 13:46

 

안녕하세요!

오늘은 Swift에서 쓰는 굉장히 유용한 기능, Copy-on-Write에 대해 알아볼 거예요.

이를 시작하기 전에, Swift에서의 컬렉션 타입부터 먼저 살펴보도록 하죠.

 

 

Swift에서 컬렉션 타입은 값 타입(Value Type)이다.

 

값 타입(Value Type)은 메모리 Stack 영역에 저장되며, 필요시 메모리의 값이 복사되어 전달되고,

참조 타입(Reference Type)은 메모리 Heap 영역에 저장되며, 필요시 메모리 주소가 전달돼요.

Swift에서 컬렉션 타입은 값 타입이라고 했기 때문에 메모리의 값이 복사되어 전달되는 것이죠.

그렇다면 한번 확인을 해볼까요?

var array1 = [1, 2, 3]
var array2 = array1

array2.append(4)

print(array1)	// [1, 2, 3]
print(array2)	// [1, 2, 3, 4]

 

위 예시에서 array1 배열을 생성 후 array2 변수에 array1 배열을 할당했어요.

array2에 새로운 값을 추가하고 나서 두 변수를 비교했을 때 값이 다른 게 보이시나요?

메모리의 값이 복사되어 전달되었기 때문에 array2에 새로운 값을 추가해도 array1에는 영향을 미치지 않는 것을 확인할 수 있어요.

 

 

컬렉션 타입이 값 타입인 경우 생길 수 있는 문제는??

 

값 타입은 메모리 Stack 영역에 저장된다고 했죠?.

그렇기 때문에 Heap 영역과는 달리 개발자가 메모리 관리를 따로 하지 않아도 된다는 장점이 있어요.

그런데 컬렉션 타입의 크기는 가변적이에요.

이 말은 컬렉션 타입에 값을 계속해서 추가하면은 그 크기 또한 점점 커진다는 것이죠.

그렇다면 크기가 커진 컬렉션 타입을 복사해서 사용한다면 컬렉션 크기만큼 메모리 사용량도 크게 차지하게 되겠죠??

그래서 Swift에서는 이를 보완하고자 Copy-on-Write라는 메커니즘을 사용하고 있어요.

 

 

Copy-on-Write란?

 

값 타입의 값을 복사하여 전달하려 할 때 실제 값이 바뀌기 전까지는 하나의 메모리 값을 공유해서 사용하는 Swift 언어의 메커니즘.

 

예시를 보면서 확인해 볼게요.

func address(of object: UnsafeRawPointer) -> String) {
	let addr = Int(bitPattern: object)
    return String(format: "%p", addr)
}

var array1 = [1, 2, 3]
var array2 = array1

print(address(of: array1))	// 0x600001720060
print(address(of: array2))	// 0x600001720060

array2.append(4)

print(address(of: array1))	// 0x600001720060
print(address(of: array2))	// 0x600002100430

 

아까의 예시처럼 array1 배열을 만들고 array2 변수에는 array1 배열을 할당했어요. 

메모리 주소를 확인해 보면 새로운 변수에 컬렉션 타입인 배열을 전달했는데도 두 변수의 메모리 주소가 동일한 게 보이시죠?

이후 array2의 값을 수정하고 나서 두 변수의 메모리 주소를 비교하면 이전과는 달리 메모리 주소가 달라진 것을 확인할 수 있어요.

어때요!? 꽤 신기하지 않나요??

 

 

참고로 Copy-on-Write 메커니즘이 적용되는 타입은 컬렉션뿐 아니라 String 타입에도 적용이 된다고 해요!