일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 백준
- ftz level13
- 재귀
- 큐
- Stack
- pwnable.kr
- 자료구조
- c언어
- HTML
- 시간복잡도
- 두근두근 자료구조
- C
- 정렬 알고리즘
- windosw 문자열
- windosws wbcs
- PHP
- OSI
- 파일 시스템
- SWiFT
- web
- Java
- 미로 탐색 알고리즘
- ftz
- LoB
- 암호수학
- 파이썬
- System
- 스택
- War Game
- level13
- Today
- Total
나의 기록, 현진록
[Swift] Struct와 Class의 특징 본문
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/#
'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 |