일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
29 | 30 | 31 |
- 백준
- 스위프트
- 연산자
- 구조체
- 옵셔널
- concurrency
- async
- 자바
- 생명주기
- 차이
- 프래그먼트
- weak
- Swift
- View
- Self
- 알고리즘
- 리스트뷰
- 풀이
- 클로저
- ios
- Subject
- RxSwift
- 테스크
- 서브스크립트
- rx
- 안드로이드
- 해시
- observable
- 프로그래머스
- 이스케이핑
- Today
- Total
study record
[Swift] 메모리 안전 본문
*이 글은 책 “스위프트 프로그래밍"을 읽고 작성한 글입니다.
스위프틑 안전을 중요시하는 언어로 컴파일러가 코드에서 위험을 줄일 수 있도록 많은 장치를 두었다. 변수를 사용하기 전에 초기화를 강제하고, 해제된 메모리에 접근할 수 없도록 설계된 것들이 그 대표적인 예이다.
스위프트는 메모리를 자동으로 관리하기 때문에 특별한 경우가 아니면 프로그래머가 메모리의 접근에 대해 신경쓸 필요가 없다. 그렇지만 메모리 접근 중 충돌이 발생할 수 있는 상황을 이해해야 메모리가 충돌할 만한 코드를 작성하지 않을 수 있다.
메모리 접근 충돌의 이해
프로그래머가 변수에 값을 할당하거나 함수의 전달인자로 변수의 값을 전달하는 등의 경우에 코드를 통해 메모리에 접근하게 된다.
// one이 저장될 메모리 위치에 쓰기 접근
var one: Int = 1
// one이 저장된 메모리 위치에 읽기 접근
print("one : \(one)")
다음과 같이 메모리 접근 충돌은 서로 다른 코드에서 동시에 같은 위치의 메모리에 접근할 때 발생한다. 동시에 여러 접근을 하게 되면 예상치 못한 결과를 얻을 수 있다.
메모리 접근의 특성
메모리 접근 충돌을 일으키는 메모리 접근에는 세 가지 특성이 있다. 다음의 세 가지 조건에 모두 해당하는 메모리 접근이 두 군데 이상의 코드에서 동시에 일어나면 메모리 접근 충돌이 발생한다.
- 최소한 한 곳에서 쓰기 접근한다.
- 같은 메모리 위치에 접근한다.
- 접근 타이밍이 겹치낟.
장기적 메모리 접근이라는 접근 방식이 있다. 장기적 메모리 접근 중에는 해당 메모리 접근이 끝나기 전에 다른 코드에서 메모리에 접근할 가능성이 있다.
접근 타이밍이 겹치게 되는 대표적 상황은 함수나 메서드에서 inout을 사용한 입출력 매개변수를 사용하는 경우나 구조체에서 mutating 키워드를 사용하는 가변 메서드를 사용하는 경우이다. 메모리의 같은 위치에 접근하는 여러 접근 타이밍이 겹친다고 해서 무조건 메모리 접근 충돌이 발생하는 것은 아니다. 그렇지만 접근 타이밍이 겹치는 경우 대개 메모리 접근 충돌이 발생할 가능성이 크다.
입출력 매개변수에서의 메모리 접근 충돌
입출력 매개변수를 갖는 함수는 동작 중 모두 장기적 메모리 접근을 한다. 즉, 함수의 실행과 동시에 입출력 매개변수의 쓰기 접근이 시작되고 함수가 종료될 때까지 쓰기 접근을 유지한다. 함수가 종료할 때 쓰기 접근을 종료한다.
입출력 매개변수를 통한 장기적 메모리 접근 중에는 매개변수로 전달하는 변수는 다른 접근이 제한된다.
메서드 내부에서 self 접근의 충돌
구조체의 가변 메서드는 메서드 실행 중에 self에 쓰기 접근을 한다.
struct GamePlayer {
var name: String
var health: Int
var energy: Int
static let maxHealth = 10
mutating func restoreHealth() {
self.health = GamePlayer.maxHealth
}
mutating func shareHealth(with teammate: inout GamepPlayer) {
balance(&teammate.health, &health)
}
}
restoreHealth()는 실행 중 인스턴스 자신인 self에 장기적으로 쓰기 접근을 한다. 메서드 내부에 인스턴스의 다른 프로퍼티를 동시에 접근하는 코드가 없다. 그러나 shareHealth()는 다른 캐릭터의 인스턴스를 입출력 매개변수로 받기 때문에 메모리 접근 충돌 여지가 있다.
입출력 매개변수와 가변 메서드를 실행하는 인스턴스가 서로 다른 메모리 위치에 있다면 메모리 접근 충돌이 발생하지 않는다.
프로퍼티 접근 중 충돌
구조체, 열거형 등은 프로퍼티로 구성되고, 튜플은 요소의 모임이다. 구조체, 열거형, 튜퓰 등은 값 타입으로, 자신의 인스턴스 내부의 프로퍼티를 변경한다는 것은 자신 스스로의 값을 변경한다는 의미로도 생각할 수 있다.
메모리 안전 때문에 구조체의 프로퍼티 메모리에 접근하는 타이밍이 겹치는 것을 무조건 제한해야 하는 것은 아니다. 다음 세가지 조건을 충족하면 구조체의 프로퍼티 메모리에 동시에 접근하더라도 안전이 보장된다.
- 연산 프로퍼티나 클래스 프로퍼티가 아닌 인스턴스의 저장 프로퍼티에만 접근
- 전역 변수가 아닌 지역 변수일 때
- 클로저에 의해 획득되지 않았거나 비탈출 클로저에 의해서만 획득 되었을 때
앞의 세 조건을 충족하지 않는 경우에는 컴파일러가 안전을 담보할 수 없기 때문에 접근을 제한할 수 있도록 오류로 취급한다.
'Swift > 스위프트 프로그래밍' 카테고리의 다른 글
[Swift] 불명확 타입 (0) | 2022.02.08 |
---|---|
[Swift] 오류 처리 (0) | 2022.02.06 |
[swift] ARC (0) | 2022.02.04 |
[Swift] where절 (0) | 2022.01.24 |
[Swift] 패턴 (0) | 2022.01.20 |