nyancoder

WWDC 2021 - Understand and eliminate hangs from your app 본문

WWDC/WWDC 2021

WWDC 2021 - Understand and eliminate hangs from your app

nyancoder 2021. 7. 3. 20:37

원본 영상: https://developer.apple.com/videos/play/wwdc2021/10258/

 

What are hangs

  • 메인 루프에서는 사용자의 입력 - 처리 - 화면에 출력의 순서로 작업이 진행됩니다.
  • 현재 작업이 느리게 처리되면 입력에 대한 화면의 갱신이 늦어지고, 사용자는 앱이 멈추는 현상을 느낄 것입니다.
  • 하나의 작업이 처리되는 중에 들어오는 이벤트는 현재의 작업이 완료된 후 처리되기 시작합니다.
  • 일반적으로 1초 이상 응답이 걸리는 경우 사용자는 앱이 멈춘 것처럼 느낍니다.
  • 뷰에 진입할 때 발생하는 지연은 스크롤할 때 발생하는 지연보다 덜 민감하게 느껴집니다.

 

What causes hangs

 

  • hang의 원인은 메인 스레드에서 많은 작업을 수행하는 경우와, 메인 스레드가 블록 되는 두 가지 경우가 있습니다.

  • 화면에 한 번에 4개의 이미지만 보여주는 앱의 경우에 상당히 많은 이미지를 미리 준비해서 로딩한다면 불필요한 지연을 만들어 낼 것입니다.
  • 이러한 경우에는 필요한 4개의 이미지만 로딩하면 메인 스레드가 처리하는 일을 줄일 수 있습니다.

  • 다른 스레드에서 처리되는 작업을 sync함수를 통해 기다리는 경우가 있습니다.
  • 이러한 작업은 메인 스레드가 불필요하게 다른 스레드를 기다리는 상태로 만듭니다.
  • 따라서 메인 스레드에서의 처리가 필요해질 때 DispatchQueue.main.async { } 함수를 통해 결과를 전달하면 불필요한 기다림을 제거할 수 있습니다.

  • 이러한 코드는 CPU에서 이미지를 비트맵으로 변환하고 UIBezier path를 적용한 뒤, 다시 비트맵을 이미지로 변환해야 합니다.
  • 이러한 잘못된 API의 사용은 더 많은 메모리 소모와 더 늦은 실행 속도를 갖게 됩니다.

 

  • 레이어에서 CoreAnimation 함수를 호출하면 둥근 모서리를 쉽게 추가할 수 있습니다.
  • 성능 또한 GPU를 사용하여 더 빠르게 처리됩니다.

  • 동기화된 API를 호출하면 호출이 끝날 때까지 스레드가 기다려야 하기 때문에 성능을 하락시킵니다.
  • 네트워크 API와 같은 경우 통신 상태가 나쁘면 API의 결과를 받기까지 오랜 시간이 걸릴 수 있기 때문에 메인 스레드에서 호출하는 것이 좋지 않습니다.

  • File I/O는 시스템 자원을 사용하는 대표적인 API로 하드웨어의 응답에 따라 수행 시간이 달라집니다.
  • 응답에 오랜 시간이 걸리는 경우 그 시간만큼 메인 스레드가 대기해야 하는 문제가 있습니다.
  • 특히 동시성이 지원되지 않는 경우 다른 스레드들에서 쓰기 작업을 수행하는 동안 메인 스레드가 읽기 작업을 수행하면, 다른 쓰기 작업들이 끝날 때까지 읽기 작업이 기다릴 수 있습니다.

  • 동기화는 메인 스레드의 지연을 만드는 또 다른 요소입니다.
  • @synchronized, .lock(), .sync(), .wait()과 같은 함수들은 대표적인 동기 함수입니다.

  • 비동기 함수를 세마포어를 통해 동기로 호출하는 것은 대표적인 피해야 할 패턴입니다.

  • 자주 변경되지 않는 값을 자주 요청해서 확인하는 것은 성능 문제를 가져올 수 있습니다.
  • 하단 메뉴에 소셜 아이콘이 있는 경우 매 페이지가 변경될 때마다 소셜 정보를 갱신하는 것은 잘 변경되지 않는 정보를 자주 갱신하는 예가 될 수 있습니다.

 

How to diagnose hangs

  • 시간 프로파일러와 시스템 프로파일러를 사용하면 문제를 진단하는데 도움을 얻을 수 있습니다.
  • 시스템 프로파일링에서 붉은 선은 시스템 호출을 나타내며 파란색 영역은 메인 스레드가 작업 중임을 나타냅니다.
  • 호출 스택에서 오래 걸린 함수를 알 수 있고, 그 함수가 얼마나 긴 시간을 소모했는지 알 수 있습니다.

 

How to eliminate hangs

  • 메인 스레드에서 이루어지는 작업의 최적화와 다른 스레드로의 작업 이전을 통해 성능을 개선할 수 있습니다.

  • 캐시는 별도의 스레드에서 주기적으로 업데이트하면 메인 스레드가 캐시에서 값을 빠르게 가져올 수 있습니다.
  • NSCache를 사용하면 데이터를 생성하는데 시간을 소모하는 대신 빠르게 메모리에서 값을 접근할 수 있습니다.

  • 데이터가 변경되었는지를 직접 체크하는 대신 변경이 발생했을 때 Notification을 받을 수 있습니다.
  • 비용이 큰 작업이 필요한 경우에도 다른 스레드에 작업을 넘기고, 처리가 완료되었을 때, Notification을 받아 응답할 수 있는 기간을 늘릴 수 있습니다.

  • 동기 API에 대응되는 비동기 API를 사용하면 메인 스레드의 응답성을 개선할 수 있습니다.
  • 비동기 API는 Asynchronously나 completion handler를 가진 함수입니다.

  • Grand Central Dispatch는 원하는 코드 블록을 동기/비동기로 다른 스레드에서 동작하게 할 수 있습니다.
  • DispatchQueue의 async 함수를 통해 다른 스레드에 작업을 넘길 수 있으며, DispatchQueue.main.async 함수를 통해 결과를 받을 수 있습니다.

  • 결과를 동기적으로 받아와야 하는 경우, 미리 async 함수를 통해 작업을 수행하고 sync를 통해 나중에 결과를 가져오는 방식으로 성능을 개선할 수 있습니다.

  • 캐시는 메모리가 더 많이 소모되며, 상태가 완전히 동기화되어있지 않을 수 있는 점을 고려해야 합니다.
  • Notification은 너무 많은 알림이 올 수 있기 때문에 빈도를 잘 결정해야 합니다.
  • 비동기 API는 스레드 우선순위가 낮을 수 있어 처리속도의 중요도에 따라 우선순위를 잘 결정해야 합니다.
  • GCD는 실행 순서가 변경될 수 있는 점을 고려하여, 작업의 순서가 중요한지를 잘 염두에 두어야 합니다.

Apple의 프레임워크와 API는 충분히 좋은 성능을 가지고 있기 때문에 이를 이용하는 것이 좋습니다.

주기적으로 앱의 성능을 개선해야 합니다.

시스템 자원은 여러 앱들의 성능에 영향을 줄 수 있기 때문에 효율적으로 사용해야 합니다.

 

Wrap up

Xcode Organizer를 통해 앱의 성능 지표를 확인해야 합니다.

hang이 잘 발생하는 좋지 않은 패턴들을 잘 숙지하고 있어야 합니다.

Instruments와 MetricKit을 사용하여 문제의 우선순위를 잘 파악해야 합니다.

Cache와 비동기 함수, GCD 등을 사용하여 발견되는 hang을 잘 제거해야 합니다.

 

목차: https://nyancoder.tistory.com/2

'WWDC > WWDC 2021' 카테고리의 다른 글

WWDC 2021 - What’s new in AVFoundation  (0) 2021.07.05
WWDC 2021 - ARC in Swift: Basics and beyond  (0) 2021.07.04
WWDC 2021 - What‘s new in Swift  (0) 2021.07.03
WWDC 2021 - Meet Xcode Cloud  (0) 2021.07.02
WWDC 2021 - Meet AsyncSequence  (0) 2021.07.01
Comments