iOS 캠프 특강 [Understanding Swift Performance] 요약

Updated:

  • 2021.03.01 월요일

재르시

  • 이재성
  • 디자인이 이쁜 앱을 만드는 것을 좋아하고, 게임 좋아하는 iOS 개발자
  • 네이버 카페팀 소속

시간복잡도와 공간복잡도 Big-O

시간 복잡도

  • 데이터 입력이 충분히 큰 것을 가정하므로 사소한 것은 무시
    • 상수항 무시
    • 영향력 없는 항 무시 (최고차항만 남김)

공간복잡도

  • 공간에 대한 개념

Swift의 시간/공간 복잡도

  • Developer Documentation에 Big-O 정보 적혀있음

Array

  • reverse(): O(n)
    • 현재 배열을 뒤집음
    • 느리지만 공간을 덜 차지
  • reversed(): O(1)
    • 뒤집힌 배열을 반환
    • 더 빠르지만 공간을 더 차지
  • 배열에서 값이 아닌 참조를 사용하면 NSArray로 사용할수 있어서 컴파일러에서 최적화 불가능
    • 값타입(구조체)를 사용하자
  • ContiguousArray: C언어 수준의 성능

Dictionary

  • 원소에 접근할때 Array보다 빠름

디버깅 용도의 print 함수 처리

디버깅 용도의 print()는 아래처럼 처리해주어 배포버전에서는 빼기 (설정의 Other Swift Flag에서 디버그 플래그 DEBUG로 설정해주기)

func printToConsole(message: string) {
    #if DEBUG
    print(mesage)
    #endif
}

오버플로우 연산자 (&+…)

  • 오버플로우 체크하는 것도 퍼포컨스에 영향줌

Stack VS Heap and ARC

Stack

  • 지역변수/매개변수 저장
  • 함수의 호출과 함께 할당되며, 호출이 완료되면 소멸

Heap

  • 동적으로 할당된 메모리는 포인터를 통해 접근
    • 변수에 직접 접근하는 것보다 느리다.
  • 큰 메모리 풀이므로 큰 배열 클래스를 할당 가능
  • 사용자가 직접 관리할 수 있고 해야만 하는 메모리영역
    • ARC에서 해줌
  • 힙은 할당시에 빈 곳을 찾고 관리하는 복잡한 과정 필요
    • 스택은 스택 포인터 변수 값만 바궈주는 정도

ARC

  • Swift는 ARC를 사용해서 앱의 메모리 사용량을 추적하고 관리
  • Heap 영역을 관리
  • thread safe하게 카운트를 Atomic하게 증감해야 한다

Weak VS Strong VS Unowned

weak

  • 약한 참조
  • 참조하는 인스턴스가 메모리에서 해제되면, ARC는 자동으로 약한 참조를 nil로 설정한다
    • 그래서 오버헤드 발생

unowned

  • 미소유 참조
  • 미소유 참조는 항상 값을 가지고 있는 것으로 간주하기 때문에 ARC는 미소유 참조의 값을 nil로 설정하지 않늗다.

Class VS Struct

Class

  • call by reference
  • 힙에 저장되어 비교적 느림

Struct

  • call by value(할당/전달시 값 복사)
  • 스택에 저장되어 비교적 빠름
  • class는 주소값만 복사하는 경우 메모리 주소크기 (8바이트)만 복사하면 되지만, struct는 항상 복사하니까 사이즈가 큰 배열을 함수로 값 전달을 해줄때마다 매번 복사가 되면 성능에 문제가 있지 않을까?
  • 그래서 COW(Copy On Write) 사용됨
    • 평소엔 메모리 주소값만 변경, 내무 값이 변경이 되는 경우에만 복사
    • COW를 위해서 class타입을 가지고 있음
    • 그래서 copy시 Reference Count 사용
  • 값이 변경될 때마다 RC 증가
struct Attachment {
    let fileURL: String
    let uuid: String
    let mimeType: String
}

struct Attachment {
    let fileURL: URL
    let uuid: UUID
    let mimeType: MimeType
}

그럼 언제 Class를 쓸까?

  • Value보단 Identity가 중요한 경우
  • 상속

Method Dispatch

  • 메서드에 대한 실행 코드의 메모리 주소를 찾는 프로세스
  • Static/Dynamic 방식
  • Dynamic방식에는 Table Dispatch/MessageDispatch 방식이 있음

Static(Direct)

  • 가장 빠른 메소드 디스패치 프로세스 중 하나
  • 컴파일러가 컴파일중에 호출해야하는 메서드를 알고 처리하는 방법

메소드 인라이닝

  • 항상 단일 작업 전용으로 작은 함수를 만드는 것이 좋다
  • 그러나 코드를 작은 함수로 분리하면 성능 비용이 발생

Dynamic

  • 클래스의 모든 메서드 주소를 저장하기 위해 포인터 배열이 생성됨
  • 이 포인터 배열은 테이블로 호출되며 런타임시 테이블 조회에 의해 적절한 동적 메서드 호출이 발생

Static VS Dynamic

  • class에 final 키워드를 사용하면 Static 사용

Leave a comment