ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • COW(Copy-on-Write) λ₯Ό μ•Œμ•„λ³΄μž
    iOS/🟠 Swift 2022. 12. 29. 23:34

    2022λ…„μ˜ λ§ˆμ§€λ§‰ λΈ”λ‘œκ·Έ 글이 될 것 κ°™λ‹€

     

    Copy-on-Write

    값을 μ‹€μ œλ‘œ μ“Έ λ•Œ (on-write) λ³΅μ‚¬ν•œλ‹€(copy)

     

    μ‹€μ œ 볡사λ₯Ό λŠ¦μΆ”μ–΄ νž™ 할당을 μ€„μ΄λŠ” μ΅œμ ν™” 방법

     

     

    Usecases

    1. Swift Collection : Array, Dictionary, String λ“±

     

    2. 3-word κ°€ λ„˜λŠ” struct λ₯Ό Protocol νƒ€μž…μœΌλ‘œ λ‹€λ£° λ•Œ 

     

     

    κ°’ νƒ€μž…κ³Ό νž™ μ˜μ—­μ˜ 관계

    Array λ‚˜ String 은 μŠ€μœ„ν”„νŠΈμ—μ„œ κ°’ νƒ€μž… μž…λ‹ˆλ‹€.

     

    κ°’ νƒ€μž… μΈμŠ€ν„΄μŠ€λŠ” 기본적으둜 μŠ€νƒ μ˜μ—­μ„ ν• λ‹Ήν•˜κ³  κ·Έ 곳에 값을 μ΄ˆκΈ°ν™”ν•˜λŠ” κ²ƒμœΌλ‘œ μ•Œλ €μ Έ μžˆμŠ΅λ‹ˆλ‹€.

     

    그러면 κ°’ νƒ€μž…κ³Ό νž™ μ˜μ—­μ€ μ–΄λ–€ 관련이 μžˆμ„κΉŒμš”?

     

    Arrray, String λ“± Collection 을 ν™œμš©ν•˜λŠ” νŠΉμ • κ°’ νƒ€μž…λ“€μ€ λŸ°νƒ€μž„에 element 의 μΆ”κ°€, μ‚­μ œκ°€ κ°€λŠ₯ν•˜κΈ° λ•Œλ¬Έμ—νž™ μ˜μ—­ 데이터λ₯Ό μœ„ν•œ 곡간을 λ‚΄λΆ€μ μœΌλ‘œ ν• λ‹Ήν•©λ‹ˆλ‹€.

     

    그런데 이 νƒ€μž…λ“€μ€ κ°’ νƒ€μž…μ΄κΈ° λ•Œλ¬Έμ— value-semantic 을 κ°€μ Έμ•Όν•©λ‹ˆλ‹€.

     

    value-semnantic 의 νŠΉμ§•μ€ 볡사할 λ•Œλ§ˆλ‹€ κΉŠμ€ 볡사가 μΌμ–΄λ‚˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

     

     μœ„ 사싀 λ•Œλ¬Έμ— 이 νƒ€μž…λ“€μ€ 값을 볡사할 λ•Œλ§ˆλ‹€ νž™ 할당이 μΌμ–΄λ‚˜μ•Όν•©λ‹ˆλ‹€.

     

    κ°’ νƒ€μž…μ˜ νŠΉμ„± λ•Œλ¬Έμ—, μΈμŠ€ν„΄μŠ€λ§ˆλ‹€ 독립적인 데이터λ₯Ό 가지고 μžˆμ–΄μ•Όν•˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.

     

     

    νž™ ν• λ‹Ήκ³Ό μ„±λŠ₯

    νž™ 할당은 κ°€λŠ₯ν•œ κ·Έ 횟수λ₯Ό μ€„μ—¬μ•Όν•˜λŠ” μ„±λŠ₯ μ €ν•΄ μš”μ†Œ 쀑 ν•˜λ‚˜μž…λ‹ˆλ‹€.

     

    Arrray, String λ“± Collection 을 ν™œμš©ν•˜λŠ” νŠΉμ • κ°’ νƒ€μž…λ“€μ€ 볡사 μ‹œ λ°œμƒν•˜λŠ” νž™ 할당을 쀄이기 μœ„ν•΄ COW λ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

     

    COW λŠ” κ°’μ˜ μˆ˜μ • λ™μž‘ λ•Œ μ‹€μ œ 볡사가 μΌμ–΄λ‚˜μ„œ 결과적으둜 νž™ ν• λ‹Ή 수λ₯Ό μ€„μ΄λŠ” μ„±λŠ₯ μ΅œμ ν™” κΈ°μˆ μž…λ‹ˆλ‹€.



    COW λ₯Ό μ‚¬μš©ν•˜λ©΄ κ°’ νƒ€μž…μ˜ μž₯점 ( No unintended sharing of state ) 을 κ°€μ Έκ°€λ©΄μ„œ value-semantic λ•Œλ¬Έμ— μƒκΈ°λŠ” λΆˆν•„μš”ν•œ νž™ 할당을 쀄일 수 μžˆμŠ΅λ‹ˆλ‹€.

     

    이 κΈ€μ—μ„œλŠ” νž™ 할당이 μ„±λŠ₯에 μ–΄λ–€ 영ν–₯을 μ£ΌλŠ”μ§€ λ‹€λ£¨μ§€λŠ” μ•ŠμŠ΅λ‹ˆλ‹€.

     

    κ΄€λ ¨ λ‚΄μš©μ€ WWDC 16: Understanding Swift Performance μ˜μƒμ„ μ°Έκ³ ν•˜μ‹œλ©΄ 쒋을 것 κ°™μŠ΅λ‹ˆλ‹€.

     

     

    νž™ μ£Όμ†Œλ₯Ό ν™•μΈν•΄μ„œ COW κ°€ μΌμ–΄λ‚˜λŠ”μ§€ 증λͺ…ν•˜κΈ°

    μ–΄λ–€ νƒ€μž…μ΄ COW κ°€ μΌμ–΄λ‚œλ‹€κ³  ν•  λ•Œ, λ‹€μŒκ³Ό 같이 λ™μž‘ν•¨μ„ μ˜ˆμƒν•  수 μžˆμŠ΅λ‹ˆλ‹€.


    1. 볡사 λ™μž‘ μ‹œμ—λŠ” λ™μΌν•œ νž™ μ˜μ—­μ„ κ³΅μœ ν•œλ‹€.


    2. μˆ˜μ • λ™μž‘μ΄ 일어날 λ•Œ 독립적인 νž™ μ˜μ—­μ„ ν• λ‹Ή/ μ΄ˆκΈ°ν™”ν•˜κ³  μˆ˜μ •μ‚¬ν•­μ„ λ°˜μ˜ν•œλ‹€.


    κ°„λ‹¨ν•œ μ½”λ“œλ‘œ 보면 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

     

    var array1 = [1,2,3]
    
    var array2 = array1 // 볡사 λ™μž‘, 이 λ•ŒλŠ” 같은 νž™ μ˜μ—­μ„ κ³΅μœ ν•œλ‹€.
    
    array2.append(4) // μˆ˜μ • λ™μž‘, array1 κ³Ό λ‹€λ₯Έ 독립적인 νž™ μ˜μ—­μ„ μ‚¬μš©ν•œλ‹€.

     

    이것을 증λͺ…ν•  λ•Œμ˜ 핡심은 μΈμŠ€ν„΄μŠ€κ°€ μ‚¬μš©ν•˜κ³  μžˆλŠ” νž™ μ˜μ—­μ˜ 포인터λ₯Ό μ–»μ–΄μ•Όν•œλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€.
    κ°’ νƒ€μž…, μ°Έμ‘° νƒ€μž…κ³Ό 관련없이 μŠ€νƒ μ˜μ—­μ€ μΈμŠ€ν„΄μŠ€λ§ˆλ‹€ 항상 λ…λ¦½μ μœΌλ‘œ ν• λ‹Ήλ˜κΈ° λ•Œλ¬Έμ—,
    μŠ€νƒ μ˜μ—­ μ£Όμ†Œλ₯Ό ν™•μΈν•˜λŠ” 것은 μ˜λ―Έκ°€ μ—†μŠ΅λ‹ˆλ‹€.

    κ·Έλ ‡λ‹€λ©΄ ν¬μΈν„°λŠ” μ–΄λ–»κ²Œ 얻을 수 μžˆμ„κΉŒμš”?
    μš°μ„  ν¬μΈν„°λŠ” μ£Όμ†Œλ₯Ό μ €μž₯ν•  수 μžˆλŠ” λ³€μˆ˜μž…λ‹ˆλ‹€.
    기본적으둜 νŠΉμ • κ°’μ—μ„œ μ–»μ–΄λ‚Έ ν¬μΈν„°λŠ” 값이 ν• λ‹Ήλœ λ©”λͺ¨λ¦¬μ˜ μ‹œμž‘μ£Όμ†Œλ₯Ό λ‹΄κ³  μžˆμŠ΅λ‹ˆλ‹€.
    C 포인터λ₯Ό μ΄ν•΄ν•˜κΈ° μœ„ν•΄ κ°„λ‹¨ν•˜κ²Œ μ •λ¦¬ν•œ λ…Έμ…˜ 링크λ₯Ό μ²¨λΆ€ν•©λ‹ˆλ‹€. (링크)

    μŠ€μœ„ν”„νŠΈλŠ” ARC λ₯Ό 톡해 λ©”λͺ¨λ¦¬λ₯Ό κ΄€λ¦¬ν•˜κ³  있고, λ©”λͺ¨λ¦¬ μ•ˆμ •μ„±μ„ μœ„ν•΄ 포인터 μ‚¬μš©μ„ μ§€μ–‘ν•©λ‹ˆλ‹€.
    ν•˜μ§€λ§Œ μŠ€μœ„νŠΈν”„λŠ” C μ–Έμ–΄μ™€μ˜ μƒν˜Έμš΄μš©μ„±μ„ μœ„ν•΄ Unsafe, Unmanaged λΌλŠ” prefix 둜 μ‹œμž‘ν•˜λŠ” API λ₯Ό μ œκ³΅ν•©λ‹ˆλ‹€.
    그리고 μŠ€μœ„ν”„νŠΈλŠ” μŠ€μœ„ν”„νŠΈ 값을 ν¬μΈν„°λ‘œ μžλ™μœΌλ‘œ λ³€ν™˜ν•΄μ£ΌλŠ” νŽΈλ¦¬ν•œ κΈ°λŠ₯을 μ œκ³΅ν•©λ‹ˆλ‹€.
    μ €λŠ” 이 κΈ°λŠ₯을 ν™œμš©ν•˜μ—¬ μΈμŠ€ν„΄μŠ€μ˜ 포인터λ₯Ό μ–»μ–΄μ„œ μ£Όμ†Œλ₯Ό 확인할 κ²ƒμž…λ‹ˆλ‹€.

    WWDC 20 Unsafe Swift 쀑

     

    주어진 μ£Όμ†Œκ°€ νž™ μ˜μ—­μΈμ§€ μŠ€νƒ μ˜μ—­μΈμ§€ μ•Œ 수 μžˆλŠ” 방법

    zsh λͺ…λ Ήμ–΄λ₯Ό 톡해 ν”„λ‘œμ„ΈμŠ€μ˜ λ©”λͺ¨λ¦¬ μ˜μ—­μ΄ μ–΄λ–»κ²Œ κ΅¬μ„±λ˜μ–΄μžˆλŠ”μ§€ ν™•μΈν•˜κ³ ,
    주어진 μ£Όμ†Œκ°€ μ–΄λ–€ μ˜μ—­μ— ν¬ν•¨λ˜λŠ”μ§€ νŒλ‹¨ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

    νž™ μ˜μ—­
    vmmap <PID> | grep Malloc
    MALLOC_TINY, MALLOC_SMALL, MALLOC_NANO λ“±μ˜ μ΄λ¦„μœΌλ‘œ ν• λ‹Ή 된 것을 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

     



    μŠ€νƒ μ˜μ—­

    vmmap <PID> | grep Stack
    thread λ§ˆλ‹€ μŠ€νƒ μ˜μ—­μ΄ ν• λ‹Ήλ˜μ—ˆκ³  각 μ˜μ—­μ˜ μ£Όμ†Œ λ²”μœ„λ₯Ό 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

     

    μ£Όμ†Œλ₯Ό μ–»λŠ” λ©”μ„œλ“œ κ΅¬ν˜„

    func address<T>(of: UnsafePointer<T>) {
          
        let result = String(format: "%018p", of)
        
        print(result)
    }
    
    /// String νž™ μ˜μ—­ 접근을 μœ„ν•΄μ„œ ν•„μš”!!
    
    func address(with: UnsafePointer<CChar>) {
    
        let result = String(format: "%018p", with)
        
        print(result)
    }

     

    Array ν™•μΈν•˜κΈ°

    UnsafePointer<Int> 둜 λ³€ν™˜ν•˜λ©΄ νž™ μ˜μ—­ μ£Όμ†Œλ₯Ό κ°€μ Έμ˜¬ 수 μžˆμŠ΅λ‹ˆλ‹€.
    * μΆ”κ°€ 정보: Array<T> λŠ” μŠ€νƒ λ‚΄ ν• λ‹Ήλ˜λŠ” μ‚¬μ΄μ¦ˆκ°€ 항상 8λ°”μ΄νŠΈμ˜€μŠ΅λ‹ˆλ‹€. (레퍼런슀만 μ €μž₯함을 μœ μΆ”ν•  수 μžˆμŠ΅λ‹ˆλ‹€)


    확인 κ²°κ³Ό Array λŠ” COW 이 μž‘λ™ν•˜λŠ” 것을 확인할 수 μžˆμ—ˆμŠ΅λ‹ˆλ‹€.

     

    String ν™•μΈν•˜κΈ°

    이번 ν•™μŠ΅μ„ 톡해 μ•Œκ²Œλœ μ‚¬μ‹€μž…λ‹ˆλ‹€.
    String 은 포인터 νƒ€μž…μ— 따라 λ‹€λ₯Έ μ£Όμ†Œλ₯Ό κ°€μ Έμ˜΅λ‹ˆλ‹€.
    UnsafePointer<String> 둜 λ³€ν™˜ν•˜λ©΄ μŠ€νƒ μ˜μ—­ μ£Όμ†Œλ₯Ό κ°€μ Έμ˜΅λ‹ˆλ‹€. (const String *)
    UnsafePointer<CChar> 둜 λ³€ν™˜ν•˜λ©΄ λ‚΄λΆ€μ μœΌλ‘œ κ΄€λ¦¬ν•˜λŠ” νž™ μ˜μ—­ μ£Όμ†Œλ₯Ό κ°€μ Έμ˜΅λ‹ˆλ‹€. (const char *)
    * μ—¬κΈ°μ„œ char * λŠ” C μ—μ„œ λ¬Έμžμ—΄ 포인터에 ν•΄λ‹Ήν•©λ‹ˆλ‹€.

     

    확인 κ²°κ³Ό String 은 COW 이 μž‘λ™ν•˜λŠ” 것을 확인할 수 μžˆμŠ΅λ‹ˆλ‹€.

    * 짧은 λ¬Έμžμ—΄μ˜ 경우 μŠ€νƒ μ˜μ—­λ§Œ μ‚¬μš©ν•˜κΈ° λ•Œλ¬Έμ— 이 λ•Œ μ–»λŠ” νž™ μ£Όμ†ŒλŠ” μ˜λ―Έμ—†λŠ” κ°’μœΌλ‘œ νŒλ‹¨ν•˜μ˜€μŠ΅λ‹ˆλ‹€.

     

    직접 COW λ₯Ό κ΅¬ν˜„ν•˜κΈ°

     

    μ•„λž˜ 링크에 μžμ„Ένžˆ λ‚˜μ™€μžˆμ–΄ μžμ„Έν•œ λ‚΄μš©μ€ μƒλž΅ν•©λ‹ˆλ‹€.
    κ΅¬ν˜„μ˜ 핡심은 struct 이 μ°Έμ‘°νƒ€μž… 속성을 톡해 indirect storage λ₯Ό 가지고,
    볡사 μ‹œ λ™μΌν•œ μ°Έμ‘°νƒ€μž… μΈμŠ€ν„΄μŠ€λ₯Ό κ³΅μœ ν•©λ‹ˆλ‹€.
    이 ν›„ 값을 μˆ˜μ •ν•  μ‹œ `isKnownUniquelyReferenced()` API λ₯Ό 톡해 μ°Έμ‘°νƒ€μž… μΈμŠ€ν„΄μŠ€μ˜ μ°Έμ‘° 개수λ₯Ό νŒŒμ•…ν•©λ‹ˆλ‹€.
    λ§Œμ•½ 1개 이상일 경우 κ·Έ λ•Œμ„œμ•Ό 독립적인 볡사본 μΈμŠ€ν„΄μŠ€λ₯Ό λ§Œλ“€κ³  κ·Έ 값을 μˆ˜μ •ν•©λ‹ˆλ‹€.

     

    GitHub - apple/swift: The Swift Programming Language

    The Swift Programming Language. Contribute to apple/swift development by creating an account on GitHub.

    github.com

     

    같이 보면 쒋은 μ˜μƒ

    μ•„λž˜λŠ” μœ„ λ‚΄μš©μ„ 잘 μ΄ν•΄ν•˜κΈ° μœ„ν•΄ 같이 보면 쒋은 μ˜μƒλ“€μž…λ‹ˆλ‹€.
    μ˜μƒμ„ 직접 보고 ν•™μŠ΅ν•˜λŠ”κ²ƒμ΄ κ°€μž₯ μ’‹μŠ΅λ‹ˆλ‹€.
    λ―Έν‘ν•˜μ§€λ§Œ μ œκ°€ μ •λ¦¬ν•œ λ…Έμ…˜ 링크λ₯Ό μΆ”κ°€λ‘œ λ‚¨κΉλ‹ˆλ‹€.

    WWDC 16 Understatnding Swift Performance [ μ˜μƒ 링크 , λ…Έμ…˜ 링크 ]
    WWDC 18 iOS Memory Deep Dive [μ˜μƒ 링크, λ…Έμ…˜ 링크]
    WWDC 20 Unsafe Swift [μ˜μƒ 링크, λ…Έμ…˜ 링크]

     

    같이 보면 쒋은 κΈ€

     

     

    μŠ€μœ„ν”„νŠΈ νƒ€μž…λ³„ λ©”λͺ¨λ¦¬ 뢄석 μ‹€ν—˜

    struct와 class κ°€ λ©”λͺ¨λ¦¬ μ˜μ—­μ„ μ–΄λ””λ₯Ό μ‚¬μš©ν•˜λŠ”μ§€ λΆ„μ„ν•œ μ‹€ν—˜ κ²°κ³Ό

    medium.com

     


    Rome was not built in a day πŸ›

     

    πŸ€– [Back to the Basics] πŸ’»
    μ£Όλ‹ˆμ–΄ iOS 개발자 우짱의 기술 λΈ”λ‘œκ·Έμž…λ‹ˆλ‹€

    λŒ“κΈ€

μ–΄μ œλ³΄λ‹€ λ°œμ „ν•œ λ‚˜