iOS 개발/Swift

[ARC] 성능을 위해 unowned를 꼭 써야할까?

스닥 2023. 2. 3. 22:00

(재미로 봐주세요..ㅎㅎ)

 

 

 

unowned를 쓰는 것은 불편합니다. 왜냐면 unowned로 참조한 친구가 사라져버리면 그 포인터가 가리키는 값이 댕글링 포인터가 되어버려서 터질 수도 있기 때문이에요.

 

 

사실 Unowned로 선언하면 옵셔널 체이닝을 안해도 되는 간편함이 있긴 하지만, 차라리 옵셔널 체이닝을 하더라도 터지지 않는 앱을 위해 상황 하나 하나를 다 들여다보는게 더 귀찮더라고요. 

 

 

그래서 전 그냥 weak를 쓰지만, 쓸 때마다 마음에 부채가 생겼습니다...;;

내가 엄청난 성능적 죄악을 저지르고 있는 것이 아닐까? 애플이 unowned를 괜히 만들지는 않았을텐데...

 

대충 이런 느낌...

 

 

 

그래서!!! 과연 얼마나 성능에 영향을 미치는지 테스트를 해봤습니다.

 

 

 

테스트는 할당과 해제를 많은 수로 반복하면서 Unowned로 선언된 변수가 참조했을 때, Weak로 선언된 변수가 참조했을 때 할당과 해제까지 얼마나 걸리는지를 보았고, 그 차이를 NanoSecond (1 / 1,000,000,000 초)로 재보았습니다.

 

 

 

 

 

비루한 m1 pro 맥북으로 돌리는거라 테스트 횟수를 많이 할 수도 없고,  이게 정말 맞는 방법인지 확실하지 않기 때문에 재미로 봐주시기 바랍니다..ㅎㅎ

 

 

 

 

 

20번을 테스트한 최종적 결과는 ...!!!

 

 

 

 

 

---------------------------------------

Unowned vs Weak 할당과 제거까지의 속도 테스트

(테스트는 100,000번의 할당과 제거를 20 반복하였습니다.)

---------------------------------------

 

...

모든 테스트 케이스

더보기

1/20 test

Unowned 소요시간: 3339171375(ns)

Weak 소요시간: 3313989000(ns)

Unowned 얼마나 빨랐을까?: -25182375(ns)

 

 

2/20 test

Unowned 소요시간: 3286848375(ns)

Weak 소요시간: 3260208667(ns)

Unowned 얼마나 빨랐을까?: -26639708(ns)

 

 

3/20 test

Unowned 소요시간: 3235051000(ns)

Weak 소요시간: 3257529791(ns)

Unowned 얼마나 빨랐을까?: 22478791(ns)

 

 

4/20 test

Unowned 소요시간: 3230886167(ns)

Weak 소요시간: 3233442375(ns)

Unowned 얼마나 빨랐을까?: 2556208(ns)

 

 

5/20 test

Unowned 소요시간: 3230484875(ns)

Weak 소요시간: 3247422125(ns)

Unowned 얼마나 빨랐을까?: 16937250(ns)

 

 

6/20 test

Unowned 소요시간: 3226592416(ns)

Weak 소요시간: 3245514833(ns)

Unowned 얼마나 빨랐을까?: 18922417(ns)

 

 

7/20 test

Unowned 소요시간: 3230438000(ns)

Weak 소요시간: 3244768583(ns)

Unowned 얼마나 빨랐을까?: 14330583(ns)

 

 

8/20 test

Unowned 소요시간: 3220529250(ns)

Weak 소요시간: 3233302875(ns)

Unowned 얼마나 빨랐을까?: 12773625(ns)

 

 

9/20 test

Unowned 소요시간: 3245940959(ns)

Weak 소요시간: 3334592458(ns)

Unowned 얼마나 빨랐을까?: 88651499(ns)

 

 

10/20 test

Unowned 소요시간: 3238710667(ns)

Weak 소요시간: 3235795208(ns)

Unowned 얼마나 빨랐을까?: -2915459(ns)

 

 

11/20 test

Unowned 소요시간: 3250374542(ns)

Weak 소요시간: 3247595333(ns)

Unowned 얼마나 빨랐을까?: -2779209(ns)

 

 

12/20 test

Unowned 소요시간: 3239318458(ns)

Weak 소요시간: 3266977666(ns)

Unowned 얼마나 빨랐을까?: 27659208(ns)

 

 

13/20 test

Unowned 소요시간: 3244912750(ns)

Weak 소요시간: 3247433125(ns)

Unowned 얼마나 빨랐을까?: 2520375(ns)

 

 

14/20 test

Unowned 소요시간: 3270567375(ns)

Weak 소요시간: 3254390958(ns)

Unowned 얼마나 빨랐을까?: -16176417(ns)

 

 

15/20 test

Unowned 소요시간: 3240328625(ns)

Weak 소요시간: 3257867917(ns)

Unowned 얼마나 빨랐을까?: 17539292(ns)

 

 

16/20 test

Unowned 소요시간: 3248741417(ns)

Weak 소요시간: 3267059333(ns)

Unowned 얼마나 빨랐을까?: 18317916(ns)

 

 

17/20 test

Unowned 소요시간: 3251601375(ns)

Weak 소요시간: 3259435375(ns)

Unowned 얼마나 빨랐을까?: 7834000(ns)

 

 

18/20 test

Unowned 소요시간: 3249609708(ns)

Weak 소요시간: 3260183500(ns)

Unowned 얼마나 빨랐을까?: 10573792(ns)

 

 

19/20 test

Unowned 소요시간: 3267382958(ns)

Weak 소요시간: 3253696292(ns)

Unowned 얼마나 빨랐을까?: -13686666(ns)

...

 

---------------------------------------

Unowned 평균 소요시간: 3087374514(ns)

Weak 평균 소요시간: 3096060270(ns)

Unowned가 평균적으로 얼마나 빨랐을까? : 8685756(ns)

---------------------------------------

 

 

 

 

 

 

 

 

결론적으로...! 정말 거의 차이가 없더라고요.

 

일단 unowned가 빠르긴 했지만, 많이 빠르진 않았고 심지어 weak가 더 빠른 테스트 케이스도 있었습니다....

 

 

 

 

10만번을 반복한 실험의 20회 평균이 8685756ns 의 차이라니!!!

 

이거 초로 환산하면... 0.008685756초의 차이밖에 안나요... 

 

 

 

물론 다른 오버헤드가 있을 수도 있겠지만 그래도 꼭 위험을 감수하면서 unowned 써야할까요??  정말 잘 모르겠네요..!ㅎㅎㅎ

 

 

 

 

누가 알려줬으면 좋겠다.  어 이거 아닌데.. 싶으면 절대 참지 말아주세요ㅎㅎ

 

 

 

 

 

 

테스트는 다음과 같이 진행하였습니다.

 

import Foundation

class TestClass {
  var value: Int = 0
}

var unownedTotal: Int = 0
var weakTotal: Int = 0

print("---------------------------------------")
print("Unowned vs Weak 할당과 제거까지의 속도 테스트")
print("(테스트는 100,000번의 할당과 제거를 20번 반복하였습니다.)")
print("---------------------------------------")
for idx in 1 ..< 20 {
    print("\(idx)/20 test")
    
    
    // Unowned
    var startTime = DispatchTime(uptimeNanoseconds: 0)
    startTime = DispatchTime.now()
    for _ in 0 ..< 100000 {
        let TestClass = TestClass()
        unowned var unownedReference: TestClass? = TestClass
        unownedReference?.value = 10
        unownedReference = nil
    }
    var endTime = DispatchTime(uptimeNanoseconds: 0)
    endTime = DispatchTime.now()
    var nanoTime = endTime.uptimeNanoseconds - startTime.uptimeNanoseconds
    print("Unowned 소요시간: \(nanoTime)(ns)")
    var temp = nanoTime

    
    // Weak
    startTime = DispatchTime.now()
    for _ in 0 ..< 100000 {
        let TestClass = TestClass()
        weak var weakReference: TestClass? = TestClass
        weakReference?.value = 10
        weakReference = nil
    }
    endTime = DispatchTime.now()
    nanoTime = endTime.uptimeNanoseconds - startTime.uptimeNanoseconds
    print("Weak 소요시간: \(nanoTime)(ns)")
    print("Unowned가 얼마나 빨랐을까?: \(Int(nanoTime) - Int(temp))(ns)\n\n")
    unownedTotal += Int(temp)
    weakTotal += Int(nanoTime)
}

print("---------------------------------------")
print("Unowned 평균 소요시간: \(unownedTotal / 20)(ns)")
print("Weak 평균 소요시간: \(weakTotal / 20)(ns)")
print("Unowned가 평균적으로 얼마나 빨랐을까? : \((weakTotal - unownedTotal) / 20)(ns)")
print("---------------------------------------")