TIL/CS(feat. Swift)

COW(Copy on Write) 훑어보기

여의도사노비 2023. 2. 16. 16:00
728x90

Copy on Write, 일명 COW는 Swift 뿐만 아니라 다른 컴퓨터 언어에도 사용되는 공통의 개념이다.

 

그렇다면 COW가 뭘까?

🤖 Copy-on-write (COW) is a technique used in computer programming and operating systems to optimize memory usage and performance when copying large data structures such as files, arrays, or other complex data types.

COW(기록 중 복사)는 파일, 배열 또는 기타 복잡한 데이터 유형과 같은 대용량 데이터 구조를 복사할 때 메모리 사용 및 성능을 최적화하기 위해 컴퓨터 프로그래밍 및 운영 체제에서 사용되는 기술입니다.

 

🙋🏻‍♂️ 쉽게 이야기하면 문자 그대로 Write(수정)이 일어날 때 Copy(복사)가 일어나는 것이다.

아래 코드를 보면서 예를들어 보자.

import Foundation

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

var arr: [String] = ["가", "나", "다"]

var array1 = arr
var array2 = arr

// 여기서 array1과 array2는 arr 배열의 값을 복사한다.
// String은 Struct로 이루어졌기 때문이다.(Class -> 참조타입 / Struct -> 값타입)

// 하지만 현재는 값을 복사하지 않고 참고하고 있는 중이다.
// 왜냐하면 값을 복사하는 것은 메모리를 할당해야하는 번거로움이 있기 때문이다.

// 그렇다면 언제 값을 복사할까?
// 바로 Write 할때이다.

address(of: array1) // 0x6000038d2140
array1[0] = "마"
address(of: array1) // 0x6000038d2dc0
// 바로 이렇게 arr의 값을 참조하고 있었던 array1은 자신의 idx 값이 바뀔때 비로소 값을 복사해온다.

 

조금 더 디테일하게 보자면?

🤖 When a process requests a copy of a data structure, instead of creating a new copy, the operating system creates a "reference" or "pointer" to the original data structure. This reference allows the process to access the original data without creating a new copy. If the process attempts to modify the data, the operating system creates a new copy of the data structure, allowing the process to make changes without affecting the original data.

프로세스가 데이터 구조의 복사본을 요청할 때 새 복사본을 만드는 대신 운영 체제는 원래 데이터 구조에 대한 "참조" 또는 "포인터"를 만듭니다. 이 참조를 통해 프로세스는 새 복사본을 만들지 않고도 원본 데이터에 액세스할 수 있습니다. 프로세스가 데이터를 수정하려고 시도하면 운영 체제는 데이터 구조의 새 복사본을 생성하여 프로세스가 원본 데이터에 영향을 주지 않고 변경할 수 있도록 합니다.

 

🙋🏻‍♂️ Swift에서는 원시타입 구조체인 Int, Double, String 그리고 Collection 타입 등의 구조체에 적용이 된다고 한다. 또한 우리가 직접 만든 사용자 정의 구조체에는 COW가 적용되지 않기 때문에 이를 직접 만들어서 구현해야한다고 한다! '그렇다면 Struct가 아닌 Class는 COW와 관련이 없겠군'이라고 생각해서 찾아보니 실제로 그렇다. 하지만 직접 구현한다면 사용자 정의 구조체에서 COW를 적용시키기 위해서 Class를 활용할 필요가 있다.

(구현 참고: https://jmkim0213.github.io/ios/swift/2019/02/18/copy_on_write.html)

 

그래서 왜 쓸까?

🤖 This technique can save time and memory, especially when dealing with large data structures. Rather than creating a new copy of a large data structure for each process that needs access to it, COW allows multiple processes to share the same data until one of them tries to modify it. This helps reduce memory usage and improve performance, especially in situations where multiple processes are working with the same data simultaneously.

이 기술은 특히 대규모 데이터 구조를 처리할 때 시간과 메모리를 절약할 수 있습니다. COW는 액세스가 필요한 각 프로세스에 대해 큰 데이터 구조의 새 복사본을 생성하는 대신 여러 프로세스가 동일한 데이터를 수정하려고 시도할 때까지 동일한 데이터를 공유할 수 있도록 합니다. 이는 특히 여러 프로세스가 동일한 데이터로 동시에 작업하는 상황에서 메모리 사용량을 줄이고 성능을 향상시키는 데 도움이 됩니다.

 

🙋🏻‍♂️ COW 관련하여 글들을 찾다보면 실제로 COW가 얼마나 유의미한지 확인해보는 실험들도 종종 있다. 비록 개인환경에서 실행하는 작은 실험이기에 엄청나게 유의미한 결과를 도출하지는 않은것 같지만(ms, ns 단위의 차이가 나는 것 같다.), 이론적으로 봤을 때 데이터의 규모가 크면 클수록 메모리 부담에 많은 차이가 날 것으로 보여진다.