나의 기록, 현진록

[Swift] Struct와 Class의 특징 본문

Programming/Swift

[Swift] Struct와 Class의 특징

guswlsdk 2025. 2. 5. 16:52
반응형

1. Struct와 Class

주요 차이점

특징 Struct Class
메모리 할당 Stack 영역, 메모리에서 값을 복사해 사용하므로 독립된 인스턴스를 생성 Heap 영역, 메모리에서 동일한 인스턴스를 여러 곳에서 참조
타입 값 타입(Value Type) 참조 타입(Reference Type)
상속 불가능 가능
성능 메모리 복사가 빨라 성능이 우수 메모리 참조로 인해 성능이 낮음

 

struct User{
    var name: String
    var age: Int
}
var a = User(name: "유현진", age: 5)
var b = User(name: "유현진 아님", age: 6)
var c = b
a.name = "유"
print(a)
print(b)
print(c)
b.name = "현"
print(a)
print(b)
print(c)


// User(name: "유", age: 5)
// User(name: "유현진 아님", age: 6)
// User(name: "유현진 아님", age: 6)
// User(name: "유", age: 5)
// User(name: "현", age: 6)
// User(name: "유현진 아님", age: 6)

 

구조체는 인스턴스마다 각각 독립적인 값을 가진다.

 

class User{
    var name: String
    var age: Int
    
    init(name: String, age: Int) {
        self.name = name
        self.age = age
    }
    
    func showInfo(){
        print(name, age)
    }
}

var a = User(name: "유현진", age: 2)
var b = a

a.showInfo()
b.showInfo()
a.name = "비둘기"
a.showInfo()
b.showInfo()

// 유현진 2
// 유현진 2
// 비둘기 2
// 비둘기 2

 

클래스는 참조 타입이기 때문에 두 개의 인스턴스가 동일한 주소에 대해 참조를 하고 있다.

b는 a를 참조하고 있기 때문에 a의 값을 바꾸면 b도 바뀌게 된다.

 

 

 

 

2. 성능 차이?

[어떠한 이유로 성능 차이가 있다는 건지에 대해 알아보자]

 

Swift는 자동으로 메모리 할당과 해제를 처리한다. 메모리 할당과 해제는 Stack 영역과 Heap 영역에서 이루어진다.

 

Stack & Heap

Stack은 컴파일 시간에 크기가 결정되며 LIFO(Last In First Out)의 매우 단순한 구조로 이루어져 Stack Pointer를 사용하여 메모리를 할당과 해제를 관리한다. 단순한 구조인 만큼 O(1)만큼의 빠른 속도로 메모리를 할당하고 해제할 수 있다. Stack의 크기는 제한적이기에 큰 데이터를 관리하기엔 적합하지 않다.

 

Heap은 프로그램이 실행될 때(런타임) 메모리 할당과 해제가 결정되며 Stack보다 복잡한 구조를 가진다. 동적으로 메모리를 할당하는 영역이기 때문이다. 메모리를 할당하기 위해서 적절한 크기만큼의 사용하지 않는 블록을 찾고, 할당한다. 해제를 위해서는 메모리를 다시 적절한 위치에 삽입해야 하는 등의 과정이 있다. 또한 Heap 영역은 Multi-Tread 환경에서 같은 주소에 메모리를 동시에 접근할 수 있기 때문에 Locking이나 동기화 매커니즘 등을 사용하여 무결성을 보장해야하기 때문에 큰 비용이 든다. Stack에 비해 속도 측면에서 성능이 떨어지는 이유라고 할 수 있다. Heap은 Stack보다 크기 제한이 유연하여 보다 큰 데이터를 다루기 적합한 영역이다. 

 

 

3. Heap Allocation 피하기

Heap Allocation이 발생할 수 있는 경우를 예를 들어 최적화할 수 있는 방법을 알아보자.

 

enum Color { case blue, green, gray }
enum Shape { case circle, rectangle, triangle }

var cache = [String : UIImage]()

func makeColorImage(color: Color, shape: Shape) -> UIImage{
    let key = "\(color):\(shape)"
    
    if let image = cache[key]{
        return image
    }
    ...
}

 

Color와 Shape에 맞는 이미지를 반환해주는 함수, 캐싱을 위한 Dictionary 타입의 cache 변수가 있다.

 

makeColorImage()에서 cache의 키는 String 타입이다.

 

String 자체는 Value Type이지만 Heap에 Reference Data를 저장한다고 한다. (https://sujinnaljin.medium.com/ios-swift%EC%9D%98-type%EA%B3%BC-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EC%A0%80%EC%9E%A5-%EA%B3%B5%EA%B0%84-25555c69ccff)

 

단순히 Dictionary 접근을 위해 String으로 키를 작성한 코드가 결국 Heap Allocation이 발생하고 성능이 떨어지는 문제를 가진다.

 

최적화 하기

enum Color { case blue, green, gray }
enum Shape { case circle, rectangle, triangle }

struct ColorImage: Hashable{
    var color: Color
    var shape: Shape
}

var cache = [ColorImage : UIImage]()

func makeColorImage(color: Color, shape: Shape) -> UIImage{
    let key = ColorImage(color: color, shape: shape)
    
    if let image = cache[key]{
        return image
    }
    ...
}

 

Key 타입을 Struct 형태로 변경하면 Stack Allocation만 발생하기 때문에 성능을 올릴 수 있다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

 

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

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

corykim0829.github.io

 

반응형

'Programming > Swift' 카테고리의 다른 글

[Swift] 강한 참조 사이클(클로저)  (0) 2025.02.07
[Swift] ARC(Automatic Reference Counting)  (1) 2025.02.06
[Swift] 15.2 필터  (0) 2021.09.14
[Swift] 15.1 맵  (0) 2021.09.14
[Swift] 14.2 빠른 종료  (0) 2021.09.13