본문 바로가기

iOS/WWDC

[WWDC 2019] Optimizing App Launch

WWDC 2019 Optimizing App Launch 를 정리한 포스트입니다.

더 자세한 내용을 원하시면 위 링크를 참조하시길 바랍니다.

 

What is launch

Launch Type

 

Cold Launch

  • 재부팅 후 (After reboot)
  • 앱이 메모리에 없음 (App is not in memory)
  • 앱 Process 가 없음 (No process exists)

 

 

앱을 시작할려면 디스크에서 메모리로 가져와야 하고

앱을 지원하는 시스템 쪽 서비스를 시작한 다음

프로세스를 실행해야 한다.

 

Warm Launch

  • 최근에 종료됨 (Recently terminated)
  • 앱이 부분적으로 메모리에 존재 (App is partially in memory)
  • 앱 Process 가 없음 (No process exists)

Resume Launch

  • 앱이 일시 중지 상태 (App is suspended)
  • 앱이 부분적으로 메모리에 존재 (App is partially in memory)
  • 앱 Process 가 없음 (No process exists)

 

우리는 사용자에게 400 milliseconds 이내에 첫 번째 프레임을 렌더링한다는 목표를 달성해야합니다.

 

Phases of App Launch 400 milliseconds

 

100 milliseconds

100 milliseconds 동안 iOS는 앱을 초기화하기 위해 필요한 시스템 측 작업을 수행합니다.


 따라서 개발자는 뷰를 생성하고 컨텐츠를 로드하는데 첫 번째 프레임을 생성하는 데 약 300 milliseconds 를 사용할 수 있습니다.

 

 

300 milliseconds

프레임이 완전히 완성 될 필요는 없습니다.

하지만 앱은  interactive and responsive 이여야 합니다.

 

 

600 milliseconds (load completed)

완성된 프레임을 표시합니다.

 

 

 

무슨일이 일어난걸까요?

 

 

System Interface

Dyld3 

동적 링커는 공유 라이브러리와 프레임워크를 로드합니다. (Dynamic Linker loads shared libraries and frameworks)

 

dyld3 를 사용하여 런타임 종속성 또는 Warm launch을 캐싱하여 속도를 크게 개선합니다. (Introduces caching of runtime dependencies to improve warm launch)

 

iOS 13 부터 적용되는 dyld3 는 최적화를 위해 2017 년 도입되었습니다. 

 

Dyld3 권장사항 

  • 사용하지 않는 프레임 워크를 연결하지 않는 것이 좋습니다. 
  • 동적 라이브러리로드를 피하는 것이 좋습니다. 이는 캐시에 잠정을 상실하기 때문입니다.
  • Hard link 로 모두 연결해야합니다.

What is the difference between a hard link and a symbolic link?

libSystem init

저수준 시스템 구성 요소로 인터페이스를 초기화합니다. (Initializes the interfaces with low level system components)

 

고정된 비용으로 시스템 측 작업 (System side work with a fixed cost)

 

Runtime Init

시스템이 Objective-C 및 Swift 런타임을 초기화 할 때입니다. (Initializes the language runtime)

 

모든 클래스 정적로드 메소드를 호출합니다. (Invokes all class static load methods)

 

일반적으로 코드에 존재하거나 링크 된 프레임 워크에서 정적 이니셜 라이저 메소드가 없다면 앱에서 아무런 작업을 수행하지 않아야 합니다.

일반적으로 정적 초기화는 권장하지 않습니다.

 

Static Runtime Initialization

프레임 워크에 전용 초기화 API 노출 (Expose dedicated initialization API in frameworks)

 

정척 초기화보다는 클래스 초기화 코드로 옮기는 것이 좋습니다. (Reduce impact to launch by avoiding +[Class load])

 

클래스 초기화는 클래스에서 처음으로 메소드를 사용할 때 느리게 호출됩니다. (Use +[Class initialize] to lazily conduct static initialization)

 

UIKit Init

시스템이 UIApplication과 UIApplicationDelegate를 인스턴스화 할 때입니다. (Instantiates the UIApplication and UIApplicationDelegate)

시스템 측 작업으로, 이벤트 처리를 설정하고 시스템과 통합합니다. (Begins event processing and integration with the system)

 

어떻게 성능을 향상시킬수 있나요?

 

Minimize work in UIApplication subclass

Minimize work in UIApplicationDelegate initialization

 

UIApplication을 서브 클래 싱하거나 UIApplicationDelegate 초기화 프로그램에서 작업을 수행하는 경우에도이 단계에 영향을 줄 수 있습니다.

 

Application Init

 

iOS 12 포함한 이전 버전

 

// Invokes UIApplicationDelegate app lifecycle callbacks 
application:willFinishLaunchingWithOptions:
application:didFinishLaunchingWithOptions: 

// Invokes UIApplicationDelegate UI lifecycle callbacks 
applicationDidBecomeActive:

 

iOS 13

UIScenes 를 채택한 경우 

 

scene:willConnectToSession:options:
sceneWillEnterForeground:
sceneDidBecomeActive:

 

 

 

Initial Frame Render

 

 

 

loadView
viewDidLoad
layoutSubviews

 

계층 구조에서 뷰 수를 줄이면 성능을 향상시킵니다. (Flatten view hierarchies and lazily load views)

Auto Layout 을 최적화합니다. (Optimize auto layout usage)

 

Auto Layout 최적화 영상: 

WWDC 2018 High Performance Auto Layout

 

Extended

최종 프레임을 사용자에게 보여줄 때입니다. (App-specific period after first frame)
비동기 데이터를 로드 할 때입니다.  (Displays asynchronously loaded data)
앱은 interactive and responsive 이어야 합니다. (App should be interactive and responsive)

 

 

 

OS signpost APIs  및 Logging을 사용하여 성능을 측정합니다. (Leverage os_signpost to measure work)

 

측정하는 방법: 

WWDC 2018 Measuring Performance Using Logging

 

 

 

How to properly measure your launch

iOS 기기는 다양한 상태와 조건에 있으며, 이는 앱 시작에 상당한 차이가 있습니다.


 따라서 앱 실행 시간 결과를 분석하고 비교할 때 같은 iOS 기기에서 버전별로 비교를 수행하는 것이 중요합니다.

 

Trading Representativeness for Consistency

네트워킹, 백그라운드 프로세스의 간섭을 제거하고 측정하는 것입니다. (Remove sources of variance to produce more consistent results)

앱 시작 시간은 일정하지 않을 수 있습니다. (May result in launch times that are not representative)

일관된 결과를 얻는 것이 더 중요합니다. (Use consistent results to evaluate progress)

 

일관된 결과를 얻는 방법:

  • 재부팅
  • 비행기 모드
  • 변하지 않는 iCloud 계정을 사용하거나 iCloud에서 완전히 로그 아웃
  • 릴리스 빌드를 사용
  • Warm launch 환경에서 측정

 

Test with Representative Data

첫 번째 프레임을 표시하는 데 필요한 데이터 만 로드해야 합니다.

가장 낮은 버전과 가장 최신의 버전의 기기로 측정합니다. 

Xcode 11의 새로운 앱 성능을 위해 새로운 XCTest를 활용할 수 있습니다.

 

Use Instruments to profile your launch

코드와 도구 모두에서 앱의 실행을 검토 할 때는 세 가지 팁과 요령을 명심해야 합니다.
즉, 먼저 작업을 최소화 한 다음 작업의 우선 순위를 정하고 마지막으로 작업을 최적화해야합니다.

 

 

Minimize

작업을 최소화 할 때 첫 번째 프레임 생성과 관련이 없는 것은 지연해야 합니다. (Defer work unrelated to first frame)

Main Thread 가 Block 되지 않아야 합니다.(Move blocking work off main thread)

메모리 할당 및 사용에는 시간이 걸릴 수 있습니다. (Reduce memory usage)

 

Prioritize

올바른 Qos로 예약되어 있는지 확인해야 합니다. (Identify the right QoS for your task)
iOS 13에서는 스케줄러에 대한 최적화를 통해 앱을 더욱 빠르게 시작할 수 있습니다. (Utilize scheduler optimizations for app launch)
우선 순위 문제 전파 작업(preserve priority issue propagate work)을 스레드 전체에 보존하는 것이 그 어느 때보 다 중요합니다. (Preserve the priority with the right primitives)

 

Optimize 

필요한 데이터, 필요한 변수와 결과를 느리게 계산하는 데이터의 양을 제한하십시오. (Simplify or limit existing work)
결과를 다르게 계산하거나 다른 데이터 구조를 사용하여 크게 개선 할 수 있습니다. (Optimize algorithms and data structures)
resources, computations 캐싱해야합니다. (Cache resources and computations)

 

참조: 

https://developer.apple.com/videos/play/wwdc2018/220

https://developer.apple.com/videos/play/wwdc2019/423/

https://blog.usejournal.com/what-is-the-difference-between-a-hard-link-and-a-symbolic-link-8c0493041b62