더 좋은 앱을 만드는 방법




개요

사용자는 앱이 버벅이지 않고 잘 작동하길 기대한다. 만약 잘 작동하지 않는다면 좋지 않은 앱으로 생각하여 지울것이다.

개발자는 앱의 지속적인 향상을 위해 아래의 4단계를 진행해야한다.

  1. 앱의 현재 퍼포먼스에 대한 정보를 수집한다
  2. 향상을 위한 가장 중요한 것을 결정한다.
  3. 앱을 프로파일링한다.
  4. 변화를 적용한다.

1

  • Xcode Organizer를 이용하여 실행되는 시간, UI 반응성, 저장소, 메모리, 배터리에 대한 진단 보고서를 볼 수 있다.
  • MetricKit을 이용하여 특정 수치들을 그래프로 보여주는 일종의 시각화 툴을 이용할 수 있다.
  • TestFlight 테스터를 이용하여 앱의 베타버전의 피드백을 얻을 수 있다.
  • 실제 사용자로부터 얻는다.

2

메모리, 디스크, 앱 실행시간, UI 등 앱의 향상을 위해 가장 중요한 것이 무엇인지 결정한다.

3

  • 응답하지 않음 및 중단 : Time Profiler 템플릿 이용
  • 메모리 이슈 : Allocation & Leaks 템플릿 사용
  • 배터리 이슈 : Energy Log 템플릿 사용
  • I/O 이슈 : File Activity 템플릿 사용
  • 네트워크 이슈 : Network 템플릿 사용

실제 장치에서 더 높은 앱 프로파일링 정확도를 가지며 퍼포먼스 이슈를 일으키는 코드를 찾는다.

그 변화는 클래스 단의 소규모 변화일 수도 앱의 아키텍쳐 변화일 수도 있다.

4

프로파일링한 변화를 구현하고, 이전 프로필과 이후 프로필에 대해 비교를 한다.

XCTest에서 측정한 퍼포먼스를 생각하며 이후의 퍼포먼스 이슈를 만들 가능성에 대해 생각해본다.




앱이 사용하는 메모리를 줄여보자

기기의 램은 앱, os, 커널과 공유하는 한정된 자원이다.

iOS 는 메모리에 대한 다양한 요구를 처리하는 기술을 가지고 있지만, 이러한 기술들은 속도와 반응성을 저하시킨다.

예를 들어 iOS는 앱이 백그라운드에서 돌아가지만 메모리에 있는 앱을 solid-state storage로 이동시킨다.

그러면 앱은 다시 foreground로 돌아가려고 할 때 지연이 발생한다.

만약 앱이 메모리를 많이 사용하면 iOS는 경고를 보낸다. 이러한 경고를 crash report에서 확인할 수 있다.

EXC_RESOURCE예외 타입과 MEMORY 서브타입을 포함한 리포트는 앱이 메모리 한계에 다다랐다는 것을 알려준다.

이 말은 iOS 가 앱을 종료시켯다라는 말이 아니고 단순히 메모리 이슈를 감지했다는 보고이다.

예외를 발생시키는 메모리 한계는 기기마다 다르다. 만약 이 제한을 넘어선다면 iOS 는 종료시킨다.

사용자가 앱을 다시 실행하면 처음부터 실행되며 백그라운드에서 가져오는 것보다 훨씬 오래걸린다.



메모리에 대한 이해

iOS 메모리 구조를 이해하기 위해선 가상 메모리와 페이징에 대한 이해가 필요하다.

iOS는 앱에게 메모리 영역을 할당해주는데 물리 램 주소가 아닌 가상 메모리 주소를 준다.

실제 램에 접근하는 일은 iOS에서 담당하며 프로그램은 가상공간 상에서 동작하게 된다.

가상공간은 온전히 프로세스에게 할당된 공간이고 프로세스에서 사용한 메모리들은 물리 램에 흩어져서 존재하게된다.

가상메모리에서 일정한 크기로 나눈 블럭을 page라고 하며 실제 메모리에서는 Frame이라고 한다.

각 프로세스는 어떤 페이지가 어떤 물리주소에 매핑되어야 하는지를 저장한 페이지 테이블을 가지고 있다.


앱이 사용하고 있는 메모리는 Clean, Dirty, Compressed로 나눠진다.

Clean 메모리는 기록될 수 있는 깨끗한 메모리를 의미한다. Memory Mapped File와 프레임워크 일부가 해당한다.

Dirty는 앱에서 수정한 데이터들, 힙 메모리 할당, 프레임워크 dirty 메모리를 포함한다.

iOS는 디스크 스왑 공간이 없다. Swap 공간은 RAM이 모두 찼을 때 RAM에서 잘 사용하지 않는 page들을 옮겨 두는 disk 공간이다.

Compressed 메모리는 일정기간동안 사용되지 않은 메모리를 압축한 것이다. iOS는 Memory compressor를 이용하여 이런 압축 작업을 한다.

앱이 사용할 수 있는 메모리는 기기별로 다른데 보통 램의 50% 미만이고 보통 70%가 넘으면 크랙이 발생한다.



메모리 측정(memory-use metric)에 대한 이해

Xcode Organizer와 MetricKit은 앱의 메모리 사용에 대해 각각의 방법을 제공한다.

첫번째 측정은 메모리 사용의 피크이다. 메모리 사용이 가장 높을 때 관찰한 샘플이다.

iOS는 주기적으로 앱의 메모리 사용을 샘플링하여 이 지표를 수집한다.

두번째 지표는 앱이 백그라운드 들어갈 때 suspend 상태를 거치는데 이 때 측정한 것이다.

iOS는 16kb인 페이지 크기를 메모리 페이지의 숫자를 곱해서 사용중인 메모리를 측정한다.


앱에서 실행가능 또는 라이브러리와 프레임워크와 관련된 자료구조는 메모리 사용 지표에 영향을 준다.

앱이 런타임에 할당하는 메모리는 처음에는 지표에 영향을 주지 않는다.

그러한 메모리는 깨끗한 것이며 iOS는 저장하기 위해 물리적 램을 할당할 필요가 없다.

앱이 할당된 메모리의 사용을 시작하면 그것은 dirty하게 되고 그 더러운 메모리는 메모리 사용지표에 기여한다.

앱을 실행하고 디버그 세션에서 앱의 프로필을 확인할 수 있다.



이미지의 메모리 적재

이미지의 메모리 사용량은 파일 크기와 관련이 있는 것이 아니라 이미지의 크기와 관련되어있다.

크기가 590kb이고 1536px X 2048px의 이미지가 있다고 생각해보자. 이 이미지의 메모리 사용량은 590kb가 아니라 1536 * 2048 * 4bytes 로 10mb정도이다.

iOS는 이미지를 메모리에 올리기 위해 load, decode, render의 단계를 거친다.

  • load : 590kb를 메모리에 올린다.
  • decode : GPU가 읽을 수 있도록 압축을 바이트 단위로 풀어 포멧을 변경한다.
  • render : 압축 해제된 코드에 따라 화면에 뿌려준다.



이미지 랜더링 포멧

  • Luminance and alpha 8 Format : 픽셀당 2Bytes로 grayscale값과 alpha 값만 지원하여 메탈 셰이딩할 때 사용
  • SRGB : 픽셀당 4Bytes로 기본 포멧
  • Wide : 픽셀당 8Bytes 더 많고 정확한 색을 표현할 수 있고 필요한 경우에만 사용

iOS는 최적의 이미지 포맷을 선택해준다.



메모리 사용을 줄이는 방법

이미지 asset의 최적화

이미지의 순수 크기가 클수록 메모리를 많이 사용한다.

앱이 보여주는 크기에 맞게 앱에서 사용하는 asset에 대해 최적화해야한다.

네트워크나 사진 앱에서 가져온 이미지와 같이 다른 곳에서 가져온 이미지리를 적절한 스케일과 색 심도로 변환해야한다.

Image I/O 프레임워크를 이용하여 최적화를 하면된다.

Core Data 작업의 사이즈를 줄여라

Core Data는 관련 NSManagedObjectContext가 저장될 때까지 NSManagedObject 인스턴스에 대한 변경사항을 메모리에 저장한다.

데이터들이 영구 저장소로 옮겨가지 전까진 메모리에 존재하며 앱ㅇ