본문 바로가기
iOS/iOS

Class의 성능을 향상 시킬 수 있는 방법들을 나열해보시오.

by 황민우 2022. 4. 7.

Allocation

- Swift는 자동으로 메모리 할당과 해제를 처리합니다. 메모리 할당과 해제는 Stack 또는 Heap에서 처리됩니다.

 

Stack

- LIFO(Last In First Out)의 단순한 구조로 메모리 할당과 해제가 편리합니다.

- StackPointer를 사용하여 할당, 해제를 처리합니다.

- 단순한 구조를 가진만큼 시간복잡도는 O(1)로 속도가 매우 빠릅니다.

- Stack은 Heap보다 비용이 더 적게 들어가며, 속도가 더 빠른 할당 방법입니다.

 

Heap

- Stack보다 더 복잡한 구조를 가지고 있습니다.

- Dynamic한 할당 방법을 사용하는데, Heap 영역에서 사용하지 않은 블록을 찾아서 메모리 할당을 처리합니다.

- 할당을 해제하기 위해서는 해당 메모리를 적절한 위치로 다시 삽입해야합니다.

- 여러 Thread가 동시에 Heap에 메모리를 할당할 수 있기 때문에, locking 또는 기타 동기화 메커니즘을 사용하여 무결성을 보호해야합니다.

*무결성 = 데이터의 정확성과 일관성이 보장된 상태(중복이나 누락이 없고, 원인과 결과가 변하지 않는 상태)

 

 

Semantics

- Semantics는 메모리 할당 시 Stack, Heap에 어디로 저장할 지 결정되는 기준입니다.

- Semantic은 어떤 타입이나 기호가 내부적으로 어떤 의미인지를 뜻하며, 두 가지 종류로 구분됩니다.

  • Value Semantics : Stack에 할당됩니다. (Struct, Enum, Tuple 및 기본타입들이 속합니다.)
  • Reference Semantics : Stack에 reference인 주소값을 할당하고, 실질적인 데이터는 Heap에 할당합니다. (대표적으로 Class와 function이 있습니다.)

- 따라서 Class의 성능을 향상시키는 첫 번째 방법은 Heap allocation을 피하는 것입니다.

- Value 타입의 자료형을 사용한다한들, String같은 경우 Heap에 Character타입으로 문자들을 간접으로 저장되기 때문에 String을 사용하게되면 Heap allocation을 사용하게 됩니다.

- 해결 방법으로는 struct를 하나 더 만들어서 key로 사용하는 것입니다.

- 이때 커스텀 객체를 collection에 사용하기 위해 Hashable이라는 프로토콜을 채택해야 합니다.


Reference Counting

- Reference Counting은 참조된 인스턴스의 개수를 세는것입니다.

- String 타입은 Character들을 Heap에 저장하며, UIFont 또한 클래스로 만들어진 객체이므로 reference counting이 발생합니다.

- 즉, 구조체는 기본적으로 레퍼런스를 사용하지 않지만, 구조체 안에서 간접적으로 레퍼런스를 사용하게 되면 reference counting으로 오버헤드를 처리하는 비용이 들게 됩니다.

 

Overhead

- 어떤 작업을 처리하기 위해 사용되는 간접적인 처리 시간, 메모리 등을 말합니다.

- 구조체의 Reference Counting 오버헤드는 구조체에 있는 레퍼런스 개수에 비례하게 됩니다.

- 구조체에서 하나 이상의 더 많은 레퍼런스를 가지게된다면, Reference Counting 오버헤드가 클래스보다 더 많이 발생하게 됩니다.


- Class의 성능을 향상시키는 두 번째 방법은 Reference Counting Overhead를 최소한으로 줄이는 것입니다.

- 그 방법으로는 UUID를 사용하는 것입니다.

- uuid 프로퍼티는 UUID라는 Struct 타입으로 대체할 수 있습니다.

- uuid의 타입을 UUID로 변경하면, Reference가 줄어들게 됩니다.

- 또한, String 대신 enum을 사용하여 오버헤드를 해결할 수도 있습니다.


Method Dispatch

- Method Dispatch는 프로그램이 어떤 메서드를 호출할 것인지 결정하여 그 메서드를 호출하는 과정을 뜻합니다.

- 어떤 메서드인지 결정하는 시점에 따라, static과 dynamic으로 나뉩니다.

 

Static Method Dispatch

- 컴파일러 시점에 컴파일러가 메서드의 실제 코드 위치를 파악할 수 있어 런타임에 찾는 과정없이 바로 해당 코드를 실행하는 것을 의미합니다.

- 구현된 코드들이 어디서 실행되는지 알 수 있기 때문에, Method Inlining(메서드 인라이닝)과 같은 코드 최적화를 적극적으로 시행합니다.

*Method Inlining : 메서드를 호출 할 때 해당 메서드로 이동하지 않고 메서드의 결괏값을 바로 반환하여 성능을 향상하는 것.

 

 

Dynamic Method Dispatch

- 컴파일 타임에 어떤 메서드를 호출하는지 판단할 수 없어 런타임에 table에 구현을 참조하여 해당 메서드에 대한 정보를 가져와서 코드를 실행시키는 것을 의미합니다.

- dynamic dispatch는 static dispatch보다 많은 비용을 필요로 하지 않고, 레퍼런스 카운팅, 힙 할당과 같은 쓰레드 동기 오버헤드가 없습니다.

- 하지만 컴파일러는 static dispatch에서는 최적화 작업이 가능하지만, dynamic dispatch에서는 컴파일러가 추론할 수 없습니다.

 

Dynamic Method Dispatch가 필요한 이유?

- dynamic dispatch가 필요한 이유는 다형성 때문입니다.

- 다형성이란, 하나의 객체가 여러 타입을 가질 수 있는것을 의미합니다.


- Class 성능을 향상시키는 세번째 방법은 컴파일러를 통해 클래스에 타입 정보에 대한 포인터를 저장하는 virtual method table을 추가하는 것입니다.

- static memory에 저장하며, 해당 테이블을 통해 메서드를 호출하게 됩니다.

- 추가적으로 SubClass를 만들지 않는다면, final을 클래스 앞에 선언하는 방법도 있습니다, 그럼 컴파일러가 static하게 dispatch 할 수 있으며 SubClass를 만들지 않는다는 의미도 알릴 수 있습니다.

 


내용 출처

https://velog.io/@leeesangheee/iOS.-class%EC%9D%98-%EC%84%B1%EB%8A%A5%EC%9D%84-%ED%96%A5%EC%83%81-%EC%8B%9C%ED%82%AC%EC%88%98-%EC%9E%88%EB%8A%94-%EB%B0%A9%EB%B2%95%EB%93%A4%EC%9D%84-%EB%82%98%EC%97%B4%ED%95%B4%EB%B3%B4%EC%8B%9C%EC%98%A4

 

iOS. class의 성능을 향상 시킬수 있는 방법들을 나열해보시오.

class의 성능을 향상 시킬수 있는 방법들을 나열해보시오.

velog.io

https://corykim0829.github.io/swift/Understanding-Swift-Performance/#

 

[Swift] 스위프트 성능 이해하기 (1) - struct와 class의 성능 차이

struct와 class의 성능에 대해 자세히 알아보자

corykim0829.github.io

 

댓글