Improve app size and runtime performance
▶ 앱 크기 및 런타임 성능 개선
1. Hi, my name is Ahmed, and I work on the Clang and Swift compilers.
▶ 안녕하세요, 제 이름은 Ahmed이고 Clang 및 Swift 컴파일러에서 일하고 있습니다.
2. In this session we're going to dive deep into changes we've made to make common Swift and Objective-C.
▶ 이 세션에서 우리는 일반적인 Swift와 Objective-C를 만들기 위해 만든 변경 사항에 대해 자세히 알아볼 것입니다.
3. operations faster and more efficient, so that we can improve your app's size and runtime performance.
▶ 작업을 더 빠르고 효율적으로 수행하여 앱의 크기와 런타임 성능을 개선할 수 있습니다.
4. When you write code in Swift or Objective-C, you're always really interacting with two major components.
▶ Swift 또는 Objective-C로 코드를 작성할 때 항상 실제로 두 가지 주요 구성 요소와 상호 작용합니다.
5. First, you build using Xcode, and that uses the Swift and Clang compilers.
▶ 먼저 Xcode를 사용하여 빌드하고 Swift 및 Clang 컴파일러를 사용합니다.
6. But when you run your app, a lot of the heavy lifting is done in the Swift and Objective-C Runtime.
▶ 그러나 앱을 실행할 때 Swift 및 Objective-C 런타임에서 많은 무거운 작업이 수행됩니다.
7. The runtime is embedded in the operating systems for all of our platforms.
▶ 런타임은 모든 플랫폼의 운영 체제에 포함되어 있습니다.
8. What the compiler cannot do at build time, the runtime does, well, at run time.
▶ 컴파일러가 빌드 타임에 할 수 없는 것을 런타임은 런타임에 합니다.
9. We're going to look at several improvements we've made in both compilers and runtimes.
▶ 컴파일러와 런타임 모두에서 수행한 몇 가지 개선 사항을 살펴보겠습니다.
10. Now, this session is a bit unusual; there are no new APIs, language changes, or new build settings.
▶ 자, 이 세션은 약간 이례적입니다. 새로운 API, 언어 변경 또는 새로운 빌드 설정이 없습니다.
11. You don't have to change your code, so all these improvements are transparent to you, the developer.
▶ 코드를 변경할 필요가 없으므로 이러한 모든 개선 사항은 개발자에게 투명합니다.
12. Let's dive in.
▶ 뛰어들어봅시다.

13. We're going to look at four improvements.
▶ 네 가지 개선 사항을 살펴보겠습니다.
14. We've made protocol checks in Swift more efficient, we've also made Objective-C message send calls smaller, as we did retain and release calls, and finally, we've made autorelease elision faster and smaller.
▶ 우리는 Swift의 프로토콜 검사를 보다 효율적으로 만들었으며, 호출을 유지 및 해제했기 때문에, Objective-C 메시지 보내기 호출을 더 작게 만들었으며, 마지막으로 자동 해제 제거를 더 빠르고 더 작게 만들었습니다.
15. Let's take a closer look.
▶ 자세히 살펴보겠습니다.
16. Let's start with protocol checks in Swift.
▶ Swift의 프로토콜 검사부터 시작하겠습니다.
17. Here we have a CustomLoggable protocol.
▶ 여기에 CustomLoggable 프로토콜이 있습니다.
18. It has a read-only computed property customLogString, and we can use it in our log function, that has special handling for CustomLoggable objects.
▶ 여기에는 읽기 전용 계산 속성인 customLogString이 있으며, CustomLoggable 개체에 대한 특수 처리가 있는 로그 함수에서 사용할 수 있습니다.
19. Later, we're defining an Event type with name and date fields.
▶ 나중에 이름 및 날짜 필드가 있는 이벤트 유형을 정의합니다.
20. And we're conforming to the CustomLoggable protocol, by defining the getter for the customLogString property.
▶ 그리고 customLogString 속성에 대한 getter를 정의하여 CustomLoggable 프로토콜을 준수합니다.
21. And this lets us pass Event objects to our 'log' function.
▶ 그리고 이를 통해 Event 객체를 'log' 함수에 전달할 수 있습니다.
22. When we execute this code, the 'log' function needs to check whether the value we passed conforms to the protocol.
▶ 이 코드를 실행할 때 'log' 함수는 우리가 전달한 값이 프로토콜을 준수하는지 확인해야 합니다.
23. And it does that using the 'as' operator.
▶ 그리고 'as' 연산자를 사용하여 수행합니다.
24. You may also have seen the 'is' operator.
▶ 'is' 연산자도 본 적이 있을 것입니다.
25. Whenever possible, this check is optimized away at build time, in the compiler.
▶ 가능할 때마다 이 검사는 컴파일러에서 빌드 시 최적화됩니다.
26. However, we don't always have enough information yet.
▶ 그러나 아직 정보가 충분하지 않습니다.
27. So, this often needs to happen in the runtime, with the help of protocol check metadata we compute earlier.
▶ 따라서, 이것은 이전에 계산한 프로토콜 검사 메타데이터의 도움으로 런타임에 발생해야 하는 경우가 많습니다.
28. With this metadata, the runtime knows whether this particular object really does conform to the protocol, and the check succeeds.
▶ 이 메타데이터를 사용하여 런타임은 이 특정 개체가 실제로 프로토콜을 준수하는지 여부를 알고 검사에 성공합니다.
29. Part of the metadata is built at compile time, but a lot can only be built at launch time, particularly when using Generics.
▶ 메타데이터의 일부는 컴파일 시간에 빌드되지만 ,많은 부분은 특히 Generics를 사용할 때 launch 시간에만 빌드할 수 있습니다.
30. When you use a lot of protocols, this can add up to hundreds of milliseconds.
▶ 많은 프로토콜을 사용하는 경우 최대 수백 밀리초가 추가될 수 있습니다.
31. On real-world apps, we've seen this take up to half of the launch time.
▶ 실제 앱에서 우리는 이것이 시작 시간의 절반까지 걸리는 것을 보았습니다.
32. With the new Swift runtime, we now precompute these ahead of time, as part of the dyld closure for the app executable and any dylib it uses at launch.
▶ 새로운 Swift 런타임을 통해, 이제 앱 실행 파일 및 시작 시 사용하는 모든 dylib에 대한 dyld 클로저의 일부로 이를 미리 미리 계산합니다.
33. Best of all, this is enabled even for existing apps when running on iOS 16, tvOS 16, or watchOS 9.
▶ 무엇보다도 iOS 16, tvOS 16 또는 watchOS 9에서 실행할 때, 기존 앱에서도 활성화됩니다.
34. If you'd like to learn more about dyld and launch closures, watch the talk "App Startup Time: Past, Present, and Future.
▶ dyld 및 launch 클로져에 대해 자세히 알아보려면 "앱 시작 시간: 과거, 현재, 미래"라는 강연을 시청하세요.
35. "That was protocol checks in Swift".
▶ "그것은 Swift의 프로토콜 검사였습니다."
36. Let's move on to message send.
▶ 메시지 보내기로 넘어갑시다.
37. With the new compilers and linker in Xcode 14, we've made message send calls up to 8 bytes smaller, down from 12, on ARM64.
▶ Xcode 14의 새로운 컴파일러와 링커를 사용하여 ARM64에서 메시지 보내기 호출을 12바이트에서 최대 8바이트로 줄였습니다.
38. As we'll see in just a moment, message send is really everywhere, so this adds up, and we've seen up to 2% code size improvements on binaries.
▶ 잠시 후 보게 되겠지만, 메시지 전송은 정말 어디에나 있습니다. 그래서 이것은 합산되고 바이너리에서 최대 2%의 코드 크기 개선을 보았습니다.
39. This is enabled automatically when building with Xcode 14, even if you use an older OS release as deployment target.
▶ 이는 이전 OS 릴리스를 배포 대상으로 사용하는 경우에도, Xcode 14로 빌드할 때 자동으로 활성화됩니다.
40. It defaults to a balance of size win and performance, but you can opt into optimizing for size only, using the objc_stubs_small linker flag.
▶ 기본적으로 사이즈 승리?와 성능의 균형이 유지되지만, objc_stubs_small 링커 플래그를 사용하여 크기만 최적화하도록 선택할 수 있습니다.
41. Now let's look into what changed.
▶ 이제 변경된 사항을 살펴보겠습니다.
42. So let's start with an example.
▶ 예를 들어 시작하겠습니다.
43. Here we're trying to make an NSDate for the start day of the conference.
▶ 여기서 우리는 컨퍼런스 시작일에 NSDate를 만들려고 합니다.
44. We start by making an NSCalendar, then we fill out NSDateComponents, make a date out of that, and finally return it.
▶ NSCalendar를 만드는 것으로 시작한 다음 NSDateComponents를 채우고 날짜를 만들고 마지막으로 반환합니다.
45. Now let's look at the assembly the compiler generates.
▶ 이제 컴파일러가 생성하는 어셈블리를 살펴보겠습니다.
46. Now, the details of the assembly aren't super important.
▶ 이제 어셈블리의 세부 사항은 그다지 중요하지 않습니다.
47. Us compiler folks stare at it all day so that you don't have to.
▶ 우리 컴파일러 사람들은 당신이 그럴 필요가 없도록 하루 종일 그것을 응시합니다.
48. What's important is that almost every line here ends up needing an instruction to call objc_msgSend, even when doing property accesses like we do for the date components.
▶ 중요한 것은 날짜 구성 요소에 대해 수행하는 것과 같은 속성 액세스를 수행하는 경우에도 여기의 거의 모든 줄에 objc_msgSend를 호출하는 명령이 필요하다는 것입니다.
49. This is because at compile time, we don't know which method to call, and it's only the objc runtime that does.
▶ 이는 컴파일 타임에 어떤 메서드를 호출할지 모르고 objc 런타임에서만 호출하기 때문입니다.
50. So we call into the runtime using objc_msgSend to ask it to find the right method.
▶ 따라서 objc_msgSend를 사용하여 런타임을 호출하여 올바른 방법을 찾도록 요청합니다.
51. Let's focus on one of these calls.
▶ 이러한 호출 중 하나에 집중해 보겠습니다.
52. We already mentioned the instruction to call objc_msgSend.
▶ 우리는 이미 objc_msgSend를 호출하는 명령을 언급했습니다.
53. But there's more.
▶ 하지만 더 있습니다.
54. To tell the runtime which method to call, we have to pass a selector to these objc_msgSend calls.
55. That needs a couple more instructions to prepare the selector.
▶ 선택기를 준비하려면 몇 가지 지침이 더 필요합니다.
56. When we look at the binary, each of these instructions takes a little bit of space.
▶ 바이너리를 볼 때, 이러한 각 명령어는 약간의 공간을 차지합니다.
57. On ARM64, that's 4 bytes each.
▶ ARM64에서는 각각 4바이트입니다.
58. So for each of these objc_msgSend calls, we're using 12 bytes, and we need that for every single one of these calls; that really adds up.
▶ 따라서 이러한 objc_msgSend 호출 각각에 대해 12바이트를 사용하고 있으며, 이러한 호출마다 12바이트가 필요합니다. 정말 추가됩니다.
59. Let's see what we can do to improve that.
▶ 이를 개선하기 위해 우리가 할 수 있는 일을 살펴보겠습니다.
60. Now, as we've seen before, 8 of those bytes are dedicated to preparing the selector.
▶ 이제 이전에 보았듯이 그 중 8바이트는 선택기를 준비하는 데 사용됩니다.
61. Interesting thing is, for any given selector, it's always the same code.
▶ 흥미로운 점은 주어진 선택기에 대해 항상 동일한 코드라는 것입니다.
62. And this is where our optimization comes in.
▶ 여기에서 최적화가 시작됩니다.
63. Since this is always the same code, we can share it and only emit it once per selector instead of every time we do a message send.
▶ 이것은 항상 동일한 코드이기 때문에 메시지를 보낼 때마다가 아니라 selector당 한 번만 내보내고 공유할 수 있습니다.
64. We can take it out and put it into a little helper function, and call that function instead.
▶ 우리는 그것을 꺼내서 작은 helper 함수에 넣고 대신 그 함수를 호출할 수 있습니다.
65. Over many calls using the same selector, we can save all these instruction bytes.
▶ 동일한 선택기를 사용하여 많은 호출을 통해 이러한 모든 명령 바이트를 저장할 수 있습니다.
66. We call this helper function a "selector stub".
▶ 이 도우미 함수를 "선택기 스텁".
67. We still need to call the real objc_msgSend function, though, so we continue onto that.
68. And again, that has another, different, indirection to load the address of the function itself and call it.
▶ 그리고 다시, 이것은 함수 자체의 주소를 로드하고 호출하기 위한 또 다른 다른 간접 참조를 가지고 있습니다.
69. The details aren't important, but what's important is that we need another several bytes of code to do that.
▶ 세부 사항은 중요하지 않지만 중요한 것은 그렇게 하려면 몇 바이트의 코드가 더 필요하다는 것입니다.
70. And this is where you can choose which mode you want, as I mentioned earlier.
▶ 그리고 여기서 앞서 언급했듯이 원하는 모드를 선택할 수 있습니다.
71. We can either keep these two little stub functions separate, like we've done here.
▶ 여기에서 했던 것처럼 이 두 개의 작은 스텁 기능을 별도로 유지할 수 있습니다.
72. We get to share the most code, and make these functions as small as possible.
▶ 우리는 가장 많은 코드를 공유하고, 이러한 기능을 가능한 한 작게 만듭니다.
73. But unfortunately, this would do two calls back to back, which is not ideal for performance.
▶ 그러나 불행히도 이것은 성능에 이상적이지 않은 두 번의 연속 호출을 수행합니다.
74. So we can further improve this with an alternative version.
▶ 그래서 우리는 이것을 대체 버전으로 더 개선할 수 있습니다.
75. We can take these two stub functions we've created, combine them into one.
▶ 우리는 우리가 만든 이 두 가지 스텁 함수를 가져와 하나로 결합할 수 있습니다.
76. That way, we keep the code closer together and we don't need as many calls.
▶ 그렇게 하면 코드를 더 가깝게 유지하고, 많은 호출이 필요하지 않습니다.
77. And that's on the right here.
▶ 그리고 여기 오른쪽에 있습니다.
78. So these are the two options.
▶ 그래서 이것은 두 가지 옵션입니다.
79. You can choose whether to optimize for size alone, and get the maximum size savings available.
▶ 크기만 최적화할지 여부를 선택하고, 사용 가능한 최대 크기 절감 효과를 얻을 수 있습니다.
80. You can enable that using the -objc_stubs_small linker flag, or you can use the code generation that provides size benefits while keeping the best performance.
▶ -objc_stubs_small 링커 플래그를 사용하여 활성화하거나 최고의 성능을 유지하면서 크기 이점을 제공하는 코드 생성을 사용할 수 있습니다.
81. And unless you're severely size-constrained, we recommend using this, and that's why it's the default.
▶ 그리고 크기가 크게 제한되지 않는 한 이것을 사용하는 것이 좋으며, 이것이 기본값인 이유입니다.
82. And that was smaller message send using stubs.
▶ 그리고 그것은 스텁을 사용하여 더 작은 메시지 전송이었습니다.
83. Another improvement we've made is making retain/release cheaper.
▶ 우리가 만든 또 다른 개선 사항은 유지/해제를 더 저렴하게 만드는 것입니다.
84. With the new compilers in Xcode 14, retain/release calls are now up to 4 bytes smaller, down from 8 on ARM64.
▶ Xcode 14의 새 컴파일러를 사용하면 ,유지/해제 호출이 ARM64의 8바이트에서 최대 4바이트 작아졌습니다.
85. As we'll see in just a moment, just like message send, retain/release is also everywhere.
▶ 잠시 후 살펴보겠지만 메시지 보내기와 마찬가지로 유지/해제도 어디에나 있습니다.
86. So this adds up, and we've seen up to 2% more code size improvements on binaries.
▶ 따라서 이것은 합산되고 바이너리에서 최대 2% 더 많은 코드 크기 개선을 보았습니다.
87. Now, unlike message send stubs, this does need runtime support, so you'll get this automatically as you migrate to a deployment target of iOS 16, tvOS 16, or watchOS 9.
▶ 이제 메시지 전송 스텁과 달리 런타임 지원이 필요하므로, iOS 16, tvOS 16 또는 watchOS 9의 배포 대상으로 마이그레이션할 때 자동으로 지원됩니다.
88. Now let's look into what changed.
▶ 이제 변경된 사항을 살펴보겠습니다.
89. Let's go back to our example.
▶ 우리의 예로 돌아가 봅시다.
90. We talked about msgSend calls, but with automatic reference counting, or ARC, we also end up with a lot of retain/release calls inserted by the compiler.
▶ 우리는 msgSend 호출에 대해 이야기했지만, 자동 참조 카운팅 또는 ARC를 사용하면 컴파일러에 의해 삽입된 많은 유지/해제 호출로 끝납니다.
91. At a very high level, whenever we make a copy of a pointer to an object, we need to increment its retain count to keep it live.
▶ 매우 높은 수준에서 개체에 대한 포인터의 복사본을 만들 때마다 유지 횟수를 늘려서 유지해야 합니다.
92. And here, this happens with our variables cal, dateComponent, and theDate.
▶ 그리고 여기에서는 cal, dateComponent 및 Date 변수에서 발생합니다.
93. We do that by calling into the runtime, using objc_retain.
▶ objc_retain을 사용하여 런타임을 호출하여 이를 수행합니다.
94. When the variables go out of scope, we then need to decrement the retain count using objc_release.
▶ 변수가 범위를 벗어나면 objc_release를 사용하여 유지 횟수를 줄여야 합니다.
95. Of course, part of the benefit of ARC is all the compiler magic that eliminates a lot of these calls, to keep them to a minimum.
▶ 물론 ARC의 이점 중 일부는 이러한 호출을 최소화하여 이러한 호출을 많이 제거하는 모든 컴파일러 마술입니다.
96. And we're going to go into one of these magic tricks a little bit later.
▶ 그리고 우리는 잠시 후에 이러한 마술 중 하나에 대해 알아볼 것입니다.
97. But even with all the magic, we still often need these calls.
▶ 그러나 모든 마법에도 불구하고, 우리는 여전히 종종 이러한 호출이 필요합니다.
98. In this example, we end up needing to release our local copies of calendar and dateComponents.
▶ 이 예에서 우리는 캘린더와 dateComponents의 로컬 복사본을 릴리스해야 합니다.
99. Under the hood, these objc_retain/release functions are just plain C functions; take a single argument, the object to be released.
▶ 내부적으로 이러한 objc_retain/release 함수는 단순한 C 함수입니다. 단일 인수, 릴리스될 객체를 취하십시오.
100. So with ARC, the compiler inserts calls to these C functions, passing the appropriate object pointers.
▶ 따라서 ARC를 사용하면 컴파일러는 이러한 C 함수에 대한 호출을 삽입하여 적절한 개체 포인터를 전달합니다.
101. Because of that, these calls have to respect the C calling convention, defined by our platform Application Binary Interface, or ABI.
▶ 그 때문에 이러한 호출은 플랫폼 애플리케이션 바이너리 인터페이스(ABI)에서 정의한 C 호출 규칙을 준수해야 합니다.
102. Concretely, what that means is that we need even more code to do these calls, to pass the pointer in the right register.
▶ 구체적으로, 이것이 의미하는 바는 올바른 레지스터에 포인터를 전달하기 위해 이러한 호출을 수행하기 위해 훨씬 더 많은 코드가 필요하다는 것입니다.
103. So we end up with a few additional 'move' instructions just for that.
▶ 그래서, 우리는 그것을 위해 몇 가지 추가 '이동' 지침으로 끝납니다.
104. And that's where our new optimization comes in.
▶ 그리고 그것이 바로 우리의 새로운 최적화가 필요한 곳입니다.
105. By specializing retain/release with a custom calling convention, we can opportunistically use the right variant depending on where the object pointer already is, so that we don't need to move it.
▶ 사용자 지정 호출 규칙으로 유지/해제를 전문화하여 개체 포인터가 이미 있는 위치에 따라 적절한 변형을 기회적으로 사용할 수 있으므로 이동할 필요가 없습니다.
106. Concretely, what this means is, we get rid of a bunch of redundant code for all these calls.
▶ 구체적으로 이것이 의미하는 바는 이러한 모든 호출에 대해 많은 중복 코드를 제거한다는 것입니다.
107. And again, while this may not seem like much for these puny little instructions, over an entire app, it really adds up.
▶ 그리고 다시 말하지만, 이 사소한 지침에 대해서는 별 것 아닌 것처럼 보일 수 있지만 전체 앱에 걸쳐 실제로 합산됩니다.
108. That's how we made retain/release operations cheaper.
▶ 이것이 우리가 유지/해제 작업을 더 저렴하게 만든 방법입니다.
109. Finally, let's talk about autorelease elision.
▶ 마지막으로 autorelease elision에 대해 이야기합시다.
110. Now this one is even more interesting.
▶ 이제 이것이 훨씬 더 흥미롭습니다.
111. With objc runtime changes, we've made autorelease elision faster.
▶ objc 런타임 변경으로, 자동 릴리스 제거가 더 빨라졌습니다.
112. That happens automatically for existing apps when you run them on the new OS releases.
▶ 이는 새 OS 릴리스에서 기존 앱을 실행할 때 자동으로 발생합니다.
113. Building on top of that, with additional compiler changes, we also made the code smaller.
▶ 그 위에 추가 컴파일러 변경으로 코드를 더 작게 만들었습니다.
114. And you'll get this size benefit automatically as you migrate to a deployment target of iOS 16, tvOS 16, or watchOS 9.
▶ 또한 iOS 16, tvOS 16 또는 watchOS 9의 배포 대상으로 마이그레이션할 때, 이 크기 이점을 자동으로 얻을 수 있습니다.
115. Now this is all great, but what's autorelease elision in the first place? Let's go back to our example.
▶ 이제 이것은 모두 훌륭하지만 처음에 autorelease elision이 무엇입니까? 우리의 예로 돌아가 봅시다.
116. I mentioned earlier that ARC already gives us a lot of compiler magic to optimize retains and releases.
▶ 앞서 ARC는 보유 및 릴리스를 최적화하기 위해 이미 많은 컴파일러 마술을 제공한다고 언급했습니다.
117. So let's focus on one case here: autoreleased return values.
▶ 따라서 여기서는 자동 릴리스된 반환 값의 한 가지 경우에 집중해 보겠습니다.
118. In this example, we made a temporary object, and we're returning it to our caller.
▶ 이 예에서 임시 객체를 만들고 호출자에게 반환합니다.
119. So let's look at how that works.
▶ 작동 방식을 살펴보겠습니다.
120. So we have our temporary theDate, we return it, the call completes, and the caller saves it to its own variable.
▶ 그래서 우리는 임시 날짜를 가지고 그것을 반환하고 호출을 완료하고 호출자는 그것을 자체 변수에 저장합니다.
121. So let's see how that works with ARC.
▶ ARC에서 어떻게 작동하는지 봅시다.
122. ARC inserts a retain in the caller, and a release in the called function.
▶ ARC는 호출자에 유지를 삽입하고 호출된 함수에 릴리스를 삽입합니다.
123. Here, when we return our temporary object, we need to release it first in the function, because it's going out of scope.
▶ 여기서 임시 객체를 반환할 때 범위를 벗어나기 때문에 함수에서 먼저 해제해야 합니다.
124. But we can't do that just yet, because it doesn't have any other references yet.
▶ 그러나 아직 다른 참조가 없기 때문에 아직 할 수 없습니다.
125. If we did release it, it would be destroyed before we even return, and that's no good.
▶ 우리가 그것을 풀어 놓으면 우리가 돌아오기도 전에 파괴될 것이고 그것은 좋지 않습니다.
126. So a special convention is used to be able to return the temporary.
▶ 따라서 임시를 반환할 수 있도록 특별한 규칙이 사용됩니다.
127. We autorelease it before the return so that the caller can then retain it.
▶ 호출자가 이를 유지할 수 있도록 반환 전에 자동 해제합니다.
128. You've likely seen autorelease and autoreleasepools before: it's simply a way to defer a release until some later point.
▶ 이전에 autorelease와 autoreleasepools를 본 적이 있을 것입니다. 이는 단순히 릴리스를 나중 시점으로 연기하는 방법일 뿐입니다.
129. Runtime doesn't really make any guarantees as to when the release happens, but as long as it's not right here, right now, it's convenient, because it lets us return this temporary object.
▶ 런타임은 릴리스가 언제 발생하는지에 대해 어떤 보장도 하지 않지만, 바로 지금 여기에 있지 않은 한 편리합니다. 이 임시 개체를 반환할 수 있기 때문입니다.
130. Now, this isn't free.
▶ 자, 이것은 무료가 아닙니다.
131. There is some overhead to doing an autorelease.
▶ 자동 릴리스를 수행하는 데 약간의 오버헤드가 있습니다.
132. This is where autorelease elision comes in.
▶ 이것은 autorelease elision이 들어오는 곳입니다.
133. So to understand how that works, let's look at the assembly and retrace this return.
▶ 작동 방식을 이해하기 위해 어셈블리를 살펴보고 이 반환을 추적해 보겠습니다.
134. When we call autorelease, that goes into the objc runtime, and that's where the fun begins.
▶ autorelease를 호출하면 objc 런타임으로 이동하고 여기서부터 재미가 시작됩니다.
135. The runtime tries to recognize what's happening: that we're returning an autoreleased value.
▶ 런타임은 무슨 일이 일어나고 있는지 인식하려고 시도합니다. 즉, 자동 릴리스된 값을 반환한다는 것입니다.
136. To help it out, the compiler emits a special marker that we never use otherwise.
▶ 이를 돕기 위해 컴파일러는 우리가 달리 사용하지 않는 특수 마커를 내보냅니다.
137. It's there to tell the runtime that this is eligible for autorelease elision.
▶ 이것이 자동 릴리스 제거에 적합하다는 것을 런타임에 알리기 위해 존재합니다.
138. And it's followed by the retain, that we will execute later.
▶ 그리고 그 뒤에는 유지가 옵니다. 이 작업은 나중에 실행할 것입니다.
139. But right now, we're still in the autorelease, and when we do it, the runtime loads the special marker instruction, as data, and compares it to see if it is the special marker value it expects.
▶ 그러나 지금 우리는 여전히 자동 릴리스에 있으며, 이를 수행할 때 런타임은 특수 마커 명령을 데이터로 로드하고 이를 비교하여 예상되는 특수 마커 값인지 확인합니다.
140. If it is, that means the compiler told the runtime that we're returning a temporary that will immediately be retained.
▶ 그렇다면 컴파일러가 런타임에 즉시 유지될 임시를 반환한다고 알렸다는 의미입니다.
141. And this lets us elide, or remove, the matching autorelease and retain calls.
▶ 그리고 이를 통해 일치하는 자동 릴리스 및 유지 호출을 생략하거나 제거할 수 있습니다.
142. And that's autorelease elision.
▶ 그리고 그것은 autorelease elision입니다.
143. However, this is not free either: loading code as data isn't something that's super common otherwise, so it's not optimal on the CPUs.
▶ 그러나 이것은 무료가 아닙니다. 코드를 데이터로 로드하는 것은 일반적이지 않으므로 CPU에서 최적이 아닙니다.
144. We can do better.
▶ 우리는 더 잘할 수 있습니다.
145. So let's retrace the return sequence again, this time using the new way.
▶ 이번에는 새로운 방법을 사용하여 반환 시퀀스를 다시 추적해 보겠습니다.
146. We started at the autorelease.
▶ 우리는 autorelease에서 시작했습니다.
147. That still goes into the Objective-C runtime.
▶ 이는 여전히 Objective-C 런타임에 포함됩니다.
148. At this point, we actually already have valuable information: the return address.
▶ 이 시점에서 우리는 이미 귀중한 정보인 return 주소를 가지고 있습니다.
149. It tells us where we need to return to after this function completes execution.
▶ 이 함수가 실행을 완료한 후 어디로 돌아가야 하는지 알려줍니다.
150. So we can keep track of that.
▶ 그래서 우리는 그것을 추적할 수 있습니다.
151. Thankfully, getting the return address is very cheap.
▶ 고맙게도 return 주소를 얻는 것은 매우 저렴합니다.
152. It's just a pointer, and we can store it on the side.
▶ 그것은 단지 포인터이고, 우리는 그것을 사이드에 저장할 수 있습니다.
153. We then leave the runtime autorelease call.
▶ 그런 다음 런타임 자동 릴리스 호출을 종료합니다.
154. We return to the caller, and we re-enter the runtime when doing the retain.
▶ 호출자에게 돌아가서 유지를 수행할 때 런타임에 다시 들어갑니다.
155. And this is where the new bit of magic happens.
▶ 그리고 여기에서 새로운 마법이 발생합니다.
156. At that point, we can look at where we are and get a pointer to our current return address.
▶ 그 시점에서 우리는 우리가 있는 곳을 보고, 현재 return 주소에 대한 포인터를 얻을 수 있습니다.
157. In the runtime, we can compare this pointer we just got while doing the retain with the one we saved earlier when we were doing the autorelease.
▶ 런타임에서 우리는 유지를 수행하는 동안 얻은 이 포인터를 이전에 자동 릴리스를 수행할 때 저장한 포인터와 비교할 수 있습니다.
158. And since we're just comparing two pointers, this is super cheap.
▶ 그리고 우리는 단지 두 개의 포인터를 비교하고 있기 때문에, 이것은 매우 저렴합니다.
159. We don't need to do expensive memory accesses.
▶ 값비싼 메모리 액세스를 수행할 필요가 없습니다.
160. If the comparison succeeds, we know we can elide the autorelease/retain pair, and we get to improve some performance.
▶ 비교가 성공하면 autorelease/retain 쌍을 생략할 수 있고, 일부 성능을 향상시킬 수 있습니다.
161. And on top of that, now that we don't need to compare this special marker instruction as data anymore, we don't need it, so we can remove it.
▶ 게다가 이제 이 특수 마커 명령어를 더 이상 데이터로 비교할 필요가 없으므로, 제거할 수 있습니다.
162. And that lets us save some code size as well.
▶ 그러면 코드 크기도 절약할 수 있습니다.
163. That's how we made autorelease elision faster and smaller.
▶ 그것이 우리가 autorelease elision을 더 빠르고 더 작게 만든 방법입니다.
164. We went through several Swift and Objective-C runtime improvements.
▶ 우리는 여러 Swift 및 Objective-C 런타임 개선 사항을 거쳤습니다.

165. Let's wrap up.
▶ 마무리하자.
166. When your app is run on the new OS, thanks to the improvements in the runtimes, Swift protocol checks are more efficient.
▶ 앱이 새로운 OS에서 실행될 때, 런타임 개선 덕분에 Swift 프로토콜 검사가 더 효율적입니다.
167. Every time we try to do autorelease elision, that's faster too.
▶ autorelease elision을 시도할 때마다 더 빠릅니다.
168. Thanks to the new compilers and linker in Xcode 14 and message send stubs, you can save up to 2% of code size by rebuilding your app.
▶ Xcode 14의 새로운 컴파일러와 링커와 메시지 전송 스텁 덕분에 앱을 다시 빌드하여 코드 크기를 최대 2%까지 절약할 수 있습니다.
169. And finally, when you update your deployment target to iOS 16, tvOS 16, or watchOS 9, you can further save another 2% by making retain/release calls smaller.
▶ 마지막으로 배포 대상을 iOS 16, tvOS 16 또는 watchOS 9로 업데이트할 때, 유지/해제 호출을 더 작게 만들어 추가로 2%를 더 절약할 수 있습니다.
170. Even more, thanks to the smaller autorelease elision sequence.
▶ 더 작은 자동 릴리스 제거 시퀀스 덕분에 더욱 그렇습니다.
171. I hope you enjoyed this deep dive into the Swift and Objective-C runtimes, and thanks for watching.
▶ Swift 및 Objective-C 런타임에 대한 심층 분석을 즐기셨기를 바랍니다. 시청해주셔서 감사합니다.
'iOS 문서 > WWDC' 카테고리의 다른 글
| [한글 번역] WWDC21 - Discover breakpoint improvements (0) | 2022.06.13 |
|---|---|
| [한글 번역] WWDC21 - Detect and diagnose memory issues (0) | 2022.06.11 |
| [한글 번역] WWDC22 - Link fast: Improve build and launch times (0) | 2022.06.11 |
댓글