ARC and
Memory Management
in Swift
Swift 에서의 Automatic Reference Counting 과 메모리 관리
@daheenallwhite!1
메모리 관리 Reference
Counting
in Swift
- Strong
- Weak
- Unowned
- Closure
Contents
2
!3
메모리 관리의 필요성
😫😫
😫
😫
😫
😫
😫😫
😫
😫
😫 😫
😫
😫
한정된 자원
😫
🖥
Process
Program
Thread
😫😫
😫
😫
😫
😫😫
😫 😫
😫
😫
😫😫
😫
😫
😫😫
😫 😫
😫
😫😫
😫
😫
😫
😫
😫
😫 😫
😫
!4
Swift 에서 메모리 사용
Code
Static
Heap
Stack Value Type
Reference Type
!5
Reference Counting
필요한 동안만 메모리에 있도록 하자!
💡
해당 instance를 참조하면 count +1
해당 instance를 필요로 하는 애들의 숫자를 세자!
6
메모리에서 class instance 생명 주기
1. Allocation : 인스턴스를 위한 메모리 공간 찾기 🔍
2. Initialization : init()
3. 인스턴스 사용
4. Deinitialization : deinit() (메모리 회수 직전)
5. Deallocation
!7
Reference Counting 적용한 코드
class Point {
var x, y: Int
init(x: Int, y: Int) {
self.x = x
self.y = y
}
}
let point1 = Point(x: 0, y: 0)
let point2 = point1
// use point1
// use point2
작성한 코드
class Point {
var refCount: Int
var x, y: Int
init(x: Int, y: Int) {
self.x = x
self.y = y
}
}
let point1 = Point(x: 0, y: 0)
let point2 = point1
retain(point2)
// use point1
release(point1)
// use point2
release(point2)
Swift 컴파일러가 ARC 적용하여 생성한 코드
!8
Reference Counting - Runtime
class Point {
var refCount: Int
var x, y: Int
init(x: Int, y: Int) {
self.x = x
self.y = y
}
}
let point1 = Point(x: 0, y: 0)
let point2 = point1
retain(point2)
// use point1
release(point1)
// use point2
release(point2)
HeapStack
point1
point2
!9
class Point {
var refCount: Int
var x, y: Int
init(x: Int, y: Int) {
self.x = x
self.y = y
}
}
let point1 = Point(x: 0, y: 0)
let point2 = point1
retain(point2)
// use point1
release(point1)
// use point2
release(point2)
HeapStack
point1
point2 refCount: 1
x: 0
y: 0
Reference Counting - Runtime
!10
class Point {
var refCount: Int
var x, y: Int
init(x: Int, y: Int) {
self.x = x
self.y = y
}
}
let point1 = Point(x: 0, y: 0)
let point2 = point1
retain(point2)
// use point1
release(point1)
// use point2
release(point2)
HeapStack
point1
point2 refCount: 1
x: 0
y: 0
Reference Counting - Runtime
!11
class Point {
var refCount: Int
var x, y: Int
init(x: Int, y: Int) {
self.x = x
self.y = y
}
}
let point1 = Point(x: 0, y: 0)
let point2 = point1
retain(point2)
// use point1
release(point1)
// use point2
release(point2)
HeapStack
point1
point2 refCount: 2
x: 0
y: 0
Reference Counting - Runtime
!12
Reference Counting - Runtime
class Point {
var refCount: Int
var x, y: Int
init(x: Int, y: Int) {
self.x = x
self.y = y
}
}
let point1 = Point(x: 0, y: 0)
let point2 = point1
retain(point2)
// use point1
release(point1)
// use point2
release(point2)
HeapStack
point1
point2 refCount: 1
x: 0
y: 0
!13
Reference Counting - Runtime
class Point {
var refCount: Int
var x, y: Int
init(x: Int, y: Int) {
self.x = x
self.y = y
}
}
let point1 = Point(x: 0, y: 0)
let point2 = point1
retain(point2)
// use point1
release(point1)
// use point2
release(point2)
HeapStack
point1
point2 refCount: 1
x: 0
y: 0
!14
class Point {
var refCount: Int
var x, y: Int
init(x: Int, y: Int) {
self.x = x
self.y = y
}
}
let point1 = Point(x: 0, y: 0)
let point2 = point1
retain(point2)
// use point1
release(point1)
// use point2
release(point2)
HeapStack
point1
point2 refCount: 0
x: 0
y: 0
Reference Counting - Runtime
!15
class Point {
var refCount: Int
var x, y: Int
init(x: Int, y: Int) {
self.x = x
self.y = y
}
}
let point1 = Point(x: 0, y: 0)
let point2 = point1
retain(point2)
// use point1
release(point1)
// use point2
release(point2)
HeapStack
point1
point2 refCount: 0
x: 0
y: 0
Reference Counting - Runtime
!16
class Point {
var refCount: Int
var x, y: Int
init(x: Int, y: Int) {
self.x = x
self.y = y
}
}
let point1 = Point(x: 0, y: 0)
let point2 = point1
retain(point2)
// use point1
release(point1)
// use point2
release(point2)
HeapStack
Reference Counting - Runtime
!17
MRC / ARC
Manual Automatic
Apple release note - Transitioning to ARC
Strong Reference
Class TabletClass User
class User {
let name: String
var tablet: Tablet?
init(name: String) {
self.name = name
print("생성: User (self.name)")
}
deinit {
print("소멸: User (self.name)")
}
}
class Tablet {
let model: String
var owner: User?
init(model: String) {
self.model = model
print("생성: Phone (self.model)")
}
deinit {
print("소멸: Phone (self.model)")
}
}
!18
🧒
!19
Strong Reference
var iPadProvar dana
<User Instance>
name: “Dana”
tablet: <Tablet Instance>
<Tablet Instance>
model: “iPad Pro”
owner: <User Instance>
var dana: User? = User(name: "Dana")
var iPadPro: Tablet? = Tablet(model: "iPad Pro")
!20
Strong Reference
var iPadProvar 흰
<Tablet Instance>
model: “iPad Pro”
owner: <User Instance>
var dana: User? = User(name: "Dana")
var iPadPro: Tablet? = Tablet(model: "iPad Pro")
// 새로 샀다!!
dana!.tablet = iPadPro
iPadPro!.owner = dana
var dana
<User Instance>
name: “Dana”
tablet: <Tablet Instance>
!21
Strong Reference Cycle
var iPadProvar 흰
<Tablet Instance>
model: “iPad Pro”
owner: <User Instance>
!21
strong strong
strong
strong
var dana
<User Instance>
name: “Dana”
tablet: <Tablet Instance>
!22
Strong Reference Cycle
var iPadProvar 흰
<Tablet Instance>
model: “iPad Pro”
owner: <User Instance>
!22
strong strong
strong
strong
// 박살남.. 😇 😭
iPadPro = nil
var dana
<User Instance>
name: “Dana”
tablet: <Tablet Instance>
!23
Strong Reference Cycle
var iPadProvar 흰
<Tablet Instance>
model: “iPad Pro”
owner: <User Instance>
!23
strong
strong
strong
var dana
<User Instance>
name: “Dana”
tablet: <Tablet Instance>
// 박살남.. 😇 😭
iPadPro = nil
!24
Strong Reference Cycle
var iPadProvar 흰
<Tablet Instance>
model: “iPad Pro”
owner: <User Instance>
!24
strong
strong
strong
// 박살남.. 😇 😭
iPadPro = nil
// 집 나감 🤬
dana = nil
var dana
<User Instance>
name: “Dana”
tablet: <Tablet Instance>
!25
Strong Reference Cycle
var iPadProvar 흰
<Tablet Instance>
model: “iPad Pro”
owner: <User Instance>
!25
strong
strong
var dana
<User Instance>
name: “Dana”
tablet: <Tablet Instance>
// 박살남.. 😇 😭
iPadPro = nil
// 집 나감 🤬
dana = nil
!26
Strong Reference Cycle
var iPadProvar 흰
<Tablet Instance>
model: “iPad Pro”
owner: <User Instance>
!26
strong
strong
// 박살남.. 😇 😭
iPadPro = nil
// 집 나감 🤬
흰 = nil
var dana
<User Instance>
name: “Dana”
tablet: <Tablet Instance>
// 박살남.. 😇 😭
iPadPro = nil
// 집 나감 🤬
dana = nil
!27
Strong Reference Cycle 해결
원인
Reference count 를 0으로 만들지 못하게 함
두 인스턴스의 상대적인 수명을 알 수 없음
해결
Strong Reference 일 때만 reference count를 세자!
상대적인 수명에 대한 정보를 미리 알려주자!
해결 방법 - weak & unowned references
weak unowned
수명>
weak
<=
unowned
해당 instance에서 참조하는 instance가
더 적은 시간동안 메모리에 있는 경우
해당 instance에서 참조하는 instance가
더 오래 혹은 같은 시간동안
메모리에 있어야 하는 경우
참조하는 속성 값 == nil
인스턴스가 있을수도/없을수도
Optional
상대 인스턴스에 의존관계인 경우
항상 있어야 할 때
Non-optional
해결 - Weak Reference
Class TabletClass User
class User {
let name: String
weak var tablet: Tablet?
init(name: String) {
self.name = name
print("생성: User (self.name)")
}
deinit {
print("소멸: User (self.name)")
}
}
class Tablet {
let model: String
var owner: User?
init(model: String) {
self.model = model
print("생성: Tablet (self.model)")
}
deinit {
print("소멸: Tablet (self.model)")
}
}
!29
🧒
해결 - Weak Reference
!30!30!30
strong strong
<User Instance>
name: “Dana”
tablet: <Tablet Instance>
weak
<Tablet Instance>
model: “iPad Pro”
owner: <User Instance>
strong
var iPadProvar dana
var dana: User? = User(name: "Dana")
var iPadPro: Tablet? = Tablet(model: "iPad Pro")
// 새로 샀다!!
dana!.tablet = iPadPro
iPadPro!.owner = dana
// 박살남
iPadPro = nil
!31!31!31
strong
weak
<Tablet Instance>
model: “iPad Pro”
owner: <User Instance>
strong
var iPadProvar 흰
<User Instance>
name: “Dana”
tablet: <Tablet Instance>
var dana
해결 - Weak Reference
var dana: User? = User(name: "Dana")
var iPadPro: Tablet? = Tablet(model: "iPad Pro")
// 새로 샀다!!
dana!.tablet = iPadPro
iPadPro!.owner = dana
// 박살남
iPadPro = nil
!32!32!32
strong
weak
var iPadPro
<User Instance>
name: “Dana”
tablet: <Tablet Instance>
var dana
해결 - Weak Reference
var dana: User? = User(name: "Dana")
var iPadPro: Tablet? = Tablet(model: "iPad Pro")
// 새로 샀다!!
dana!.tablet = iPadPro
iPadPro!.owner = dana
// 박살남
iPadPro = nil
!33!33!33
strong
var iPadPro
<User Instance>
name: “Dana”
tablet: <Tablet Instance>
var dana
nil
// 집 나감 🤬
dana = nil
해결 - Weak Reference
var dana: User? = User(name: "Dana")
var iPadPro: Tablet? = Tablet(model: "iPad Pro")
// 새로 샀다!!
dana!.tablet = iPadPro
iPadPro!.owner = dana
// 박살남
iPadPro = nil
!34!34!34
strong
var iPadPro
<User Instance>
name: “Dana”
tablet: <Tablet Instance>
var dana
nil
해결 - Weak Reference
// 집 나감 🤬
dana = nil
var dana: User? = User(name: "Dana")
var iPadPro: Tablet? = Tablet(model: "iPad Pro")
// 새로 샀다!!
dana!.tablet = iPadPro
iPadPro!.owner = dana
// 박살남
iPadPro = nil
!35!35!35
var iPadPro
<User Instance>
name: “Dana”
tablet: <Tablet Instance>
var dana
nil
해결 - Weak Reference
// 집 나감 🤬
dana = nil
var dana: User? = User(name: "Dana")
var iPadPro: Tablet? = Tablet(model: "iPad Pro")
// 새로 샀다!!
dana!.tablet = iPadPro
iPadPro!.owner = dana
// 박살남
iPadPro = nil
!36!36!36
var iPadProvar dana
해결 - Weak Reference
// 집 나감 🤬
dana = nil
var dana: User? = User(name: "Dana")
var iPadPro: Tablet? = Tablet(model: "iPad Pro")
// 새로 샀다!!
dana!.tablet = iPadPro
iPadPro!.owner = dana
// 박살남
iPadPro = nil
!37!37!37
Unowned Reference
Class NetflixMembershipClass User
class NetflixMembership {
let plan: String
let owner: User
init(plan: String, owner: User) {
self.plan = plan
self.owner = owner
print("생성: (self.plan) 구독")
}
deinit {
print("소멸: (self.plan) 구독")
}
}
class User {
let name: String
var netflixMembership:
NetflixMembership?
init(name: String) {
self.name = name
print("생성: User (self.name)")
}
deinit {
print("소멸: User (self.name)")
}
}
unowned let owner: User
🧒
!38!38!38
해결 - Unowned Reference
var dana
var dana: User? = User(name: “Dana")
dana!.netflixMembership = NetflixMembership(plan: "Premium", owner: dana!)
!39!39!39
var 흰
strong
<User Instance>
name: “Dana”
streamingMembership: 

<StreamingMembership Instance>
var dana
해결 - Unowned Reference
var dana: User? = User(name: “Dana")
dana!.netflixMembership = NetflixMembership(plan: "Premium", owner: dana!)
!40!40!40
strong
<NetflixMembership Instance>
Plan : “Premium”
owner: <User Instance>
strong
<User Instance>
name: “Dana”
streamingMembership: 

<StreamingMembership Instance>
var dana
해결 - Unowned Reference
var dana: User? = User(name: “Dana")
dana!.netflixMembership = NetflixMembership(plan: "Premium", owner: dana!)
!41!41!41
strong
<NetflixMembership Instance>
Plan : “Premium”
owner: <User Instance>
strong
unowned
<User Instance>
name: “Dana”
streamingMembership: 

<StreamingMembership Instance>
var dana
해결 - Unowned Reference
var dana: User? = User(name: “Dana")
dana!.netflixMembership = NetflixMembership(plan: "Premium", owner: dana!)
!42!42!42
strong
<NetflixMembership Instance>
Plan : “Premium”
owner: <User Instance>
strong
unowned
// 탈퇴..
Dana = nil
<User Instance>
name: “Dana”
streamingMembership: 

<StreamingMembership Instance>
var dana
var dana: User? = User(name: “Dana")
dana!.netflixMembership = NetflixMembership(plan: "Premium", owner: dana!)
해결 - Unowned Reference
!43!43!43
<NetflixMembership Instance>
Plan : “Premium”
owner: <User Instance>
strong
unowned
// 탈퇴..
Dana = nil
<User Instance>
name: “Dana”
streamingMembership: 

<StreamingMembership Instance>
var dana
var dana: User? = User(name: “Dana")
dana!.netflixMembership = NetflixMembership(plan: "Premium", owner: dana!)
해결 - Unowned Reference
!44!44!44
<NetflixMembership Instance>
Plan : “Premium”
owner: <User Instance>
unowned
// 탈퇴..
Dana = nil
var dana
var dana: User? = User(name: “Dana")
dana!.netflixMembership = NetflixMembership(plan: "Premium", owner: dana!)
해결 - Unowned Reference
!45!45!45
// 탈퇴..
Dana = nil
var dana
var dana: User? = User(name: “Dana")
dana!.netflixMembership = NetflixMembership(plan: "Premium", owner: dana!)
해결 - Unowned Reference
!46
Strong Reference Cycle for Closure
class User {
let name: String
var nickName: String?
init(name: String, nickName: String? = nil) {
self.name = name
self.nickName = nickName
}
lazy var completeUserName: () -> String = {
if let nickName = self.nickName {
return "(self.name) ((nickName))"
} else {
return "(self.name)"
}
}
deinit {
print("탈퇴: User (self.name)")
}
}
class User {
let name: String
var nickName: String?
init(name: String, nickName: String? = nil) {
self.name = name
self.nickName = nickName
}
lazy var completeUserName: () -> String = {
if let nickName = self.nickName {
return "(self.name) ((nickName))"
} else {
return "(self.name)"
}
}
deinit {
print("탈퇴: User (self.name)")
}
}
!47
Strong Reference Cycle for Closure
var dana: User? =
User(name: "Dana", nickName: "white")
print(dana!.completeUserName())
dana = nil
var dana
<User Instance>
name: “Dana”
nickName: “white”
completeUserName: 

( ) -> String
( ) -> String
self.name self.nickName
strong
strong
strong
!48
Strong Reference Cycle for Closure
var 흰
( ) -> String
self.name self.nickName
strong
class User {
let name: String
var nickName: String?
init(name: String, nickName: String? = nil) {
self.name = name
self.nickName = nickName
}
lazy var completeUserName: () -> String = {
if let nickName = self.nickName {
return "(self.name) ((nickName))"
} else {
return "(self.name)"
}
}
deinit {
print("탈퇴: User (self.name)")
}
}
strong
var dana
<User Instance>
name: “Dana”
nickName: “white”
completeUserName: 

( ) -> String
var dana: User? =
User(name: "Dana", nickName: "white")
print(dana!.completeUserName())
dana = nil
class User {
let name: String
var nickName: String?
init(name: String, nickName: String? = nil) {
self.name = name
self.nickName = nickName
}
lazy var completeUserName: () -> String = {
[unowned self] in
if let nickName = self.nickName {
return "(self.name) ((nickName))"
} else {
return "(self.name)"
}
}
deinit {
print("탈퇴: User (self.name)")
}
}
!49
var 흰
( ) -> String
self.name self.nickName
unowned
strong
strong
해결 - Capture List
var dana
<User Instance>
name: “Dana”
nickName: “white”
completeUserName: 

( ) -> String
var dana: User? =
User(name: "Dana", nickName: "white")
print(dana!.completeUserName())
dana = nil
class User {
let name: String
var nickName: String?
init(name: String, nickName: String? = nil) {
self.name = name
self.nickName = nickName
}
lazy var completeUserName: () -> String = {
[unowned self] in
if let nickName = self.nickName {
return "(self.name) ((nickName))"
} else {
return "(self.name)"
}
}
deinit {
print("탈퇴: User (self.name)")
}
}
!50
var 흰
( ) -> String
self.name self.nickName
unowned
strong
var dana
<User Instance>
name: “Dana”
nickName: “white”
completeUserName: 

( ) -> String
해결 - Capture List
var dana: User? =
User(name: "Dana", nickName: "white")
print(dana!.completeUserName())
dana = nil
class User {
let name: String
var nickName: String?
init(name: String, nickName: String? = nil) {
self.name = name
self.nickName = nickName
}
lazy var completeUserName: () -> String = {
[unowned self] in
if let nickName = self.nickName {
return "(self.name) ((nickName))"
} else {
return "(self.name)"
}
}
deinit {
print("탈퇴: User (self.name)")
}
}
!51
( ) -> String
self.name self.nickName
unowned
var dana
해결 - Capture List
var dana: User? =
User(name: "Dana", nickName: "white")
print(dana!.completeUserName())
dana = nil
class User {
let name: String
var nickName: String?
init(name: String, nickName: String? = nil) {
self.name = name
self.nickName = nickName
}
lazy var completeUserName: () -> String = {
[unowned self] in
if let nickName = self.nickName {
return "(self.name) ((nickName))"
} else {
return "(self.name)"
}
}
deinit {
print("탈퇴: User (self.name)")
}
}
!52
var dana
해결 - Capture List
var dana: User? =
User(name: "Dana", nickName: "white")
print(dana!.completeUserName())
dana = nil
!53
Summary 📌
메모리 관리 필요성
Reference Counting : 필요로 하는 애들의 수를 세자
Swift Compiler, ARC / MRC
Strong Reference Cycle : 메모리 공간 낭비의 원인
Weak / Unowned : 상대적 수명에 대한 정보를 제공해주자
Closure : of Reference Type. Capture List
!54
Strong / Weak / Unowned
raywenderlich - ARC and Memory Management in Swift
!55
Reference 📗
✦ Swift Language Guide - Automatic Reference Counting
✦ raywenderlich - ARC and Memory Management in Swift
✦ WWDC 2015 - Optimizing Swift Performance
✦ WWDC 2016 - Understanding Swift Performance
✦ ARC Release Note
✦ Soulpark blog - Automatic Reference Counting (ARC)
!56
더 알아보기 🔍
✦ Value type이 메모리에서 관리되는 방식
✦ Understanding Swift Performance - WWDC 2016
✦ 메모리 관리 방식을 고려한 Swift 성능 올리기
✦ Optimizing Swift Performance - WWDC 2015
✦ Understanding Swift Performance - WWDC 2016
✦ Object-C 에서 MRC/ARC
✦ ARC obj-c
✦ Transition to ARC (no longer supported?)
✦ 고급언어의 컴파일러와 프로그램의 로딩
✦ Garbage Collector 와 ARC 의 차이

Swift - ARC와 메모리 관리

  • 1.
    ARC and Memory Management inSwift Swift 에서의 Automatic Reference Counting 과 메모리 관리 @daheenallwhite!1
  • 2.
    메모리 관리 Reference Counting inSwift - Strong - Weak - Unowned - Closure Contents 2
  • 3.
    !3 메모리 관리의 필요성 😫😫 😫 😫 😫 😫 😫😫 😫 😫 😫😫 😫 😫 한정된 자원 😫 🖥 Process Program Thread 😫😫 😫 😫 😫 😫😫 😫 😫 😫 😫 😫😫 😫 😫 😫😫 😫 😫 😫 😫😫 😫 😫 😫 😫 😫 😫 😫 😫
  • 4.
    !4 Swift 에서 메모리사용 Code Static Heap Stack Value Type Reference Type
  • 5.
    !5 Reference Counting 필요한 동안만메모리에 있도록 하자! 💡 해당 instance를 참조하면 count +1 해당 instance를 필요로 하는 애들의 숫자를 세자!
  • 6.
    6 메모리에서 class instance생명 주기 1. Allocation : 인스턴스를 위한 메모리 공간 찾기 🔍 2. Initialization : init() 3. 인스턴스 사용 4. Deinitialization : deinit() (메모리 회수 직전) 5. Deallocation
  • 7.
    !7 Reference Counting 적용한코드 class Point { var x, y: Int init(x: Int, y: Int) { self.x = x self.y = y } } let point1 = Point(x: 0, y: 0) let point2 = point1 // use point1 // use point2 작성한 코드 class Point { var refCount: Int var x, y: Int init(x: Int, y: Int) { self.x = x self.y = y } } let point1 = Point(x: 0, y: 0) let point2 = point1 retain(point2) // use point1 release(point1) // use point2 release(point2) Swift 컴파일러가 ARC 적용하여 생성한 코드
  • 8.
    !8 Reference Counting -Runtime class Point { var refCount: Int var x, y: Int init(x: Int, y: Int) { self.x = x self.y = y } } let point1 = Point(x: 0, y: 0) let point2 = point1 retain(point2) // use point1 release(point1) // use point2 release(point2) HeapStack point1 point2
  • 9.
    !9 class Point { varrefCount: Int var x, y: Int init(x: Int, y: Int) { self.x = x self.y = y } } let point1 = Point(x: 0, y: 0) let point2 = point1 retain(point2) // use point1 release(point1) // use point2 release(point2) HeapStack point1 point2 refCount: 1 x: 0 y: 0 Reference Counting - Runtime
  • 10.
    !10 class Point { varrefCount: Int var x, y: Int init(x: Int, y: Int) { self.x = x self.y = y } } let point1 = Point(x: 0, y: 0) let point2 = point1 retain(point2) // use point1 release(point1) // use point2 release(point2) HeapStack point1 point2 refCount: 1 x: 0 y: 0 Reference Counting - Runtime
  • 11.
    !11 class Point { varrefCount: Int var x, y: Int init(x: Int, y: Int) { self.x = x self.y = y } } let point1 = Point(x: 0, y: 0) let point2 = point1 retain(point2) // use point1 release(point1) // use point2 release(point2) HeapStack point1 point2 refCount: 2 x: 0 y: 0 Reference Counting - Runtime
  • 12.
    !12 Reference Counting -Runtime class Point { var refCount: Int var x, y: Int init(x: Int, y: Int) { self.x = x self.y = y } } let point1 = Point(x: 0, y: 0) let point2 = point1 retain(point2) // use point1 release(point1) // use point2 release(point2) HeapStack point1 point2 refCount: 1 x: 0 y: 0
  • 13.
    !13 Reference Counting -Runtime class Point { var refCount: Int var x, y: Int init(x: Int, y: Int) { self.x = x self.y = y } } let point1 = Point(x: 0, y: 0) let point2 = point1 retain(point2) // use point1 release(point1) // use point2 release(point2) HeapStack point1 point2 refCount: 1 x: 0 y: 0
  • 14.
    !14 class Point { varrefCount: Int var x, y: Int init(x: Int, y: Int) { self.x = x self.y = y } } let point1 = Point(x: 0, y: 0) let point2 = point1 retain(point2) // use point1 release(point1) // use point2 release(point2) HeapStack point1 point2 refCount: 0 x: 0 y: 0 Reference Counting - Runtime
  • 15.
    !15 class Point { varrefCount: Int var x, y: Int init(x: Int, y: Int) { self.x = x self.y = y } } let point1 = Point(x: 0, y: 0) let point2 = point1 retain(point2) // use point1 release(point1) // use point2 release(point2) HeapStack point1 point2 refCount: 0 x: 0 y: 0 Reference Counting - Runtime
  • 16.
    !16 class Point { varrefCount: Int var x, y: Int init(x: Int, y: Int) { self.x = x self.y = y } } let point1 = Point(x: 0, y: 0) let point2 = point1 retain(point2) // use point1 release(point1) // use point2 release(point2) HeapStack Reference Counting - Runtime
  • 17.
    !17 MRC / ARC ManualAutomatic Apple release note - Transitioning to ARC
  • 18.
    Strong Reference Class TabletClassUser class User { let name: String var tablet: Tablet? init(name: String) { self.name = name print("생성: User (self.name)") } deinit { print("소멸: User (self.name)") } } class Tablet { let model: String var owner: User? init(model: String) { self.model = model print("생성: Phone (self.model)") } deinit { print("소멸: Phone (self.model)") } } !18 🧒
  • 19.
    !19 Strong Reference var iPadProvardana <User Instance> name: “Dana” tablet: <Tablet Instance> <Tablet Instance> model: “iPad Pro” owner: <User Instance> var dana: User? = User(name: "Dana") var iPadPro: Tablet? = Tablet(model: "iPad Pro")
  • 20.
    !20 Strong Reference var iPadProvar흰 <Tablet Instance> model: “iPad Pro” owner: <User Instance> var dana: User? = User(name: "Dana") var iPadPro: Tablet? = Tablet(model: "iPad Pro") // 새로 샀다!! dana!.tablet = iPadPro iPadPro!.owner = dana var dana <User Instance> name: “Dana” tablet: <Tablet Instance>
  • 21.
    !21 Strong Reference Cycle variPadProvar 흰 <Tablet Instance> model: “iPad Pro” owner: <User Instance> !21 strong strong strong strong var dana <User Instance> name: “Dana” tablet: <Tablet Instance>
  • 22.
    !22 Strong Reference Cycle variPadProvar 흰 <Tablet Instance> model: “iPad Pro” owner: <User Instance> !22 strong strong strong strong // 박살남.. 😇 😭 iPadPro = nil var dana <User Instance> name: “Dana” tablet: <Tablet Instance>
  • 23.
    !23 Strong Reference Cycle variPadProvar 흰 <Tablet Instance> model: “iPad Pro” owner: <User Instance> !23 strong strong strong var dana <User Instance> name: “Dana” tablet: <Tablet Instance> // 박살남.. 😇 😭 iPadPro = nil
  • 24.
    !24 Strong Reference Cycle variPadProvar 흰 <Tablet Instance> model: “iPad Pro” owner: <User Instance> !24 strong strong strong // 박살남.. 😇 😭 iPadPro = nil // 집 나감 🤬 dana = nil var dana <User Instance> name: “Dana” tablet: <Tablet Instance>
  • 25.
    !25 Strong Reference Cycle variPadProvar 흰 <Tablet Instance> model: “iPad Pro” owner: <User Instance> !25 strong strong var dana <User Instance> name: “Dana” tablet: <Tablet Instance> // 박살남.. 😇 😭 iPadPro = nil // 집 나감 🤬 dana = nil
  • 26.
    !26 Strong Reference Cycle variPadProvar 흰 <Tablet Instance> model: “iPad Pro” owner: <User Instance> !26 strong strong // 박살남.. 😇 😭 iPadPro = nil // 집 나감 🤬 흰 = nil var dana <User Instance> name: “Dana” tablet: <Tablet Instance> // 박살남.. 😇 😭 iPadPro = nil // 집 나감 🤬 dana = nil
  • 27.
    !27 Strong Reference Cycle해결 원인 Reference count 를 0으로 만들지 못하게 함 두 인스턴스의 상대적인 수명을 알 수 없음 해결 Strong Reference 일 때만 reference count를 세자! 상대적인 수명에 대한 정보를 미리 알려주자!
  • 28.
    해결 방법 -weak & unowned references weak unowned 수명> weak <= unowned 해당 instance에서 참조하는 instance가 더 적은 시간동안 메모리에 있는 경우 해당 instance에서 참조하는 instance가 더 오래 혹은 같은 시간동안 메모리에 있어야 하는 경우 참조하는 속성 값 == nil 인스턴스가 있을수도/없을수도 Optional 상대 인스턴스에 의존관계인 경우 항상 있어야 할 때 Non-optional
  • 29.
    해결 - WeakReference Class TabletClass User class User { let name: String weak var tablet: Tablet? init(name: String) { self.name = name print("생성: User (self.name)") } deinit { print("소멸: User (self.name)") } } class Tablet { let model: String var owner: User? init(model: String) { self.model = model print("생성: Tablet (self.model)") } deinit { print("소멸: Tablet (self.model)") } } !29 🧒
  • 30.
    해결 - WeakReference !30!30!30 strong strong <User Instance> name: “Dana” tablet: <Tablet Instance> weak <Tablet Instance> model: “iPad Pro” owner: <User Instance> strong var iPadProvar dana var dana: User? = User(name: "Dana") var iPadPro: Tablet? = Tablet(model: "iPad Pro") // 새로 샀다!! dana!.tablet = iPadPro iPadPro!.owner = dana // 박살남 iPadPro = nil
  • 31.
    !31!31!31 strong weak <Tablet Instance> model: “iPadPro” owner: <User Instance> strong var iPadProvar 흰 <User Instance> name: “Dana” tablet: <Tablet Instance> var dana 해결 - Weak Reference var dana: User? = User(name: "Dana") var iPadPro: Tablet? = Tablet(model: "iPad Pro") // 새로 샀다!! dana!.tablet = iPadPro iPadPro!.owner = dana // 박살남 iPadPro = nil
  • 32.
    !32!32!32 strong weak var iPadPro <User Instance> name:“Dana” tablet: <Tablet Instance> var dana 해결 - Weak Reference var dana: User? = User(name: "Dana") var iPadPro: Tablet? = Tablet(model: "iPad Pro") // 새로 샀다!! dana!.tablet = iPadPro iPadPro!.owner = dana // 박살남 iPadPro = nil
  • 33.
    !33!33!33 strong var iPadPro <User Instance> name:“Dana” tablet: <Tablet Instance> var dana nil // 집 나감 🤬 dana = nil 해결 - Weak Reference var dana: User? = User(name: "Dana") var iPadPro: Tablet? = Tablet(model: "iPad Pro") // 새로 샀다!! dana!.tablet = iPadPro iPadPro!.owner = dana // 박살남 iPadPro = nil
  • 34.
    !34!34!34 strong var iPadPro <User Instance> name:“Dana” tablet: <Tablet Instance> var dana nil 해결 - Weak Reference // 집 나감 🤬 dana = nil var dana: User? = User(name: "Dana") var iPadPro: Tablet? = Tablet(model: "iPad Pro") // 새로 샀다!! dana!.tablet = iPadPro iPadPro!.owner = dana // 박살남 iPadPro = nil
  • 35.
    !35!35!35 var iPadPro <User Instance> name:“Dana” tablet: <Tablet Instance> var dana nil 해결 - Weak Reference // 집 나감 🤬 dana = nil var dana: User? = User(name: "Dana") var iPadPro: Tablet? = Tablet(model: "iPad Pro") // 새로 샀다!! dana!.tablet = iPadPro iPadPro!.owner = dana // 박살남 iPadPro = nil
  • 36.
    !36!36!36 var iPadProvar dana 해결- Weak Reference // 집 나감 🤬 dana = nil var dana: User? = User(name: "Dana") var iPadPro: Tablet? = Tablet(model: "iPad Pro") // 새로 샀다!! dana!.tablet = iPadPro iPadPro!.owner = dana // 박살남 iPadPro = nil
  • 37.
    !37!37!37 Unowned Reference Class NetflixMembershipClassUser class NetflixMembership { let plan: String let owner: User init(plan: String, owner: User) { self.plan = plan self.owner = owner print("생성: (self.plan) 구독") } deinit { print("소멸: (self.plan) 구독") } } class User { let name: String var netflixMembership: NetflixMembership? init(name: String) { self.name = name print("생성: User (self.name)") } deinit { print("소멸: User (self.name)") } } unowned let owner: User 🧒
  • 38.
    !38!38!38 해결 - UnownedReference var dana var dana: User? = User(name: “Dana") dana!.netflixMembership = NetflixMembership(plan: "Premium", owner: dana!)
  • 39.
    !39!39!39 var 흰 strong <User Instance> name:“Dana” streamingMembership: <StreamingMembership Instance> var dana 해결 - Unowned Reference var dana: User? = User(name: “Dana") dana!.netflixMembership = NetflixMembership(plan: "Premium", owner: dana!)
  • 40.
    !40!40!40 strong <NetflixMembership Instance> Plan :“Premium” owner: <User Instance> strong <User Instance> name: “Dana” streamingMembership: <StreamingMembership Instance> var dana 해결 - Unowned Reference var dana: User? = User(name: “Dana") dana!.netflixMembership = NetflixMembership(plan: "Premium", owner: dana!)
  • 41.
    !41!41!41 strong <NetflixMembership Instance> Plan :“Premium” owner: <User Instance> strong unowned <User Instance> name: “Dana” streamingMembership: <StreamingMembership Instance> var dana 해결 - Unowned Reference var dana: User? = User(name: “Dana") dana!.netflixMembership = NetflixMembership(plan: "Premium", owner: dana!)
  • 42.
    !42!42!42 strong <NetflixMembership Instance> Plan :“Premium” owner: <User Instance> strong unowned // 탈퇴.. Dana = nil <User Instance> name: “Dana” streamingMembership: <StreamingMembership Instance> var dana var dana: User? = User(name: “Dana") dana!.netflixMembership = NetflixMembership(plan: "Premium", owner: dana!) 해결 - Unowned Reference
  • 43.
    !43!43!43 <NetflixMembership Instance> Plan :“Premium” owner: <User Instance> strong unowned // 탈퇴.. Dana = nil <User Instance> name: “Dana” streamingMembership: <StreamingMembership Instance> var dana var dana: User? = User(name: “Dana") dana!.netflixMembership = NetflixMembership(plan: "Premium", owner: dana!) 해결 - Unowned Reference
  • 44.
    !44!44!44 <NetflixMembership Instance> Plan :“Premium” owner: <User Instance> unowned // 탈퇴.. Dana = nil var dana var dana: User? = User(name: “Dana") dana!.netflixMembership = NetflixMembership(plan: "Premium", owner: dana!) 해결 - Unowned Reference
  • 45.
    !45!45!45 // 탈퇴.. Dana =nil var dana var dana: User? = User(name: “Dana") dana!.netflixMembership = NetflixMembership(plan: "Premium", owner: dana!) 해결 - Unowned Reference
  • 46.
    !46 Strong Reference Cyclefor Closure class User { let name: String var nickName: String? init(name: String, nickName: String? = nil) { self.name = name self.nickName = nickName } lazy var completeUserName: () -> String = { if let nickName = self.nickName { return "(self.name) ((nickName))" } else { return "(self.name)" } } deinit { print("탈퇴: User (self.name)") } }
  • 47.
    class User { letname: String var nickName: String? init(name: String, nickName: String? = nil) { self.name = name self.nickName = nickName } lazy var completeUserName: () -> String = { if let nickName = self.nickName { return "(self.name) ((nickName))" } else { return "(self.name)" } } deinit { print("탈퇴: User (self.name)") } } !47 Strong Reference Cycle for Closure var dana: User? = User(name: "Dana", nickName: "white") print(dana!.completeUserName()) dana = nil var dana <User Instance> name: “Dana” nickName: “white” completeUserName: ( ) -> String ( ) -> String self.name self.nickName strong strong strong
  • 48.
    !48 Strong Reference Cyclefor Closure var 흰 ( ) -> String self.name self.nickName strong class User { let name: String var nickName: String? init(name: String, nickName: String? = nil) { self.name = name self.nickName = nickName } lazy var completeUserName: () -> String = { if let nickName = self.nickName { return "(self.name) ((nickName))" } else { return "(self.name)" } } deinit { print("탈퇴: User (self.name)") } } strong var dana <User Instance> name: “Dana” nickName: “white” completeUserName: ( ) -> String var dana: User? = User(name: "Dana", nickName: "white") print(dana!.completeUserName()) dana = nil
  • 49.
    class User { letname: String var nickName: String? init(name: String, nickName: String? = nil) { self.name = name self.nickName = nickName } lazy var completeUserName: () -> String = { [unowned self] in if let nickName = self.nickName { return "(self.name) ((nickName))" } else { return "(self.name)" } } deinit { print("탈퇴: User (self.name)") } } !49 var 흰 ( ) -> String self.name self.nickName unowned strong strong 해결 - Capture List var dana <User Instance> name: “Dana” nickName: “white” completeUserName: ( ) -> String var dana: User? = User(name: "Dana", nickName: "white") print(dana!.completeUserName()) dana = nil
  • 50.
    class User { letname: String var nickName: String? init(name: String, nickName: String? = nil) { self.name = name self.nickName = nickName } lazy var completeUserName: () -> String = { [unowned self] in if let nickName = self.nickName { return "(self.name) ((nickName))" } else { return "(self.name)" } } deinit { print("탈퇴: User (self.name)") } } !50 var 흰 ( ) -> String self.name self.nickName unowned strong var dana <User Instance> name: “Dana” nickName: “white” completeUserName: ( ) -> String 해결 - Capture List var dana: User? = User(name: "Dana", nickName: "white") print(dana!.completeUserName()) dana = nil
  • 51.
    class User { letname: String var nickName: String? init(name: String, nickName: String? = nil) { self.name = name self.nickName = nickName } lazy var completeUserName: () -> String = { [unowned self] in if let nickName = self.nickName { return "(self.name) ((nickName))" } else { return "(self.name)" } } deinit { print("탈퇴: User (self.name)") } } !51 ( ) -> String self.name self.nickName unowned var dana 해결 - Capture List var dana: User? = User(name: "Dana", nickName: "white") print(dana!.completeUserName()) dana = nil
  • 52.
    class User { letname: String var nickName: String? init(name: String, nickName: String? = nil) { self.name = name self.nickName = nickName } lazy var completeUserName: () -> String = { [unowned self] in if let nickName = self.nickName { return "(self.name) ((nickName))" } else { return "(self.name)" } } deinit { print("탈퇴: User (self.name)") } } !52 var dana 해결 - Capture List var dana: User? = User(name: "Dana", nickName: "white") print(dana!.completeUserName()) dana = nil
  • 53.
    !53 Summary 📌 메모리 관리필요성 Reference Counting : 필요로 하는 애들의 수를 세자 Swift Compiler, ARC / MRC Strong Reference Cycle : 메모리 공간 낭비의 원인 Weak / Unowned : 상대적 수명에 대한 정보를 제공해주자 Closure : of Reference Type. Capture List
  • 54.
    !54 Strong / Weak/ Unowned raywenderlich - ARC and Memory Management in Swift
  • 55.
    !55 Reference 📗 ✦ SwiftLanguage Guide - Automatic Reference Counting ✦ raywenderlich - ARC and Memory Management in Swift ✦ WWDC 2015 - Optimizing Swift Performance ✦ WWDC 2016 - Understanding Swift Performance ✦ ARC Release Note ✦ Soulpark blog - Automatic Reference Counting (ARC)
  • 56.
    !56 더 알아보기 🔍 ✦Value type이 메모리에서 관리되는 방식 ✦ Understanding Swift Performance - WWDC 2016 ✦ 메모리 관리 방식을 고려한 Swift 성능 올리기 ✦ Optimizing Swift Performance - WWDC 2015 ✦ Understanding Swift Performance - WWDC 2016 ✦ Object-C 에서 MRC/ARC ✦ ARC obj-c ✦ Transition to ARC (no longer supported?) ✦ 고급언어의 컴파일러와 프로그램의 로딩 ✦ Garbage Collector 와 ARC 의 차이