추상적으로 "메모리를 관리해주는 것" 으로 이해하고 있었지만, JAVA 의 GC ( 가비지 컬렉터 ) 와의 차이점을 명확하게 설명하게 어려워서 포스팅을 작성했습니다.
프로그래밍 언어의 메모리 관리
C, C++ 과 같은 언어는 Heap 영역에 할당된 메모리를 개발자가 직접 관리하지만 대부분의 현대적인 언어들은 포인터를 언어 내부적으로 사용하고 ( 감추고 ) 메모리를 자동적으로 관리합니다. 이에 크게 두가지 방식이 있습니다.
RC ( Reference Count )
사용 언어: Swift, Rust ...
참조 시점: Complie time
특정 객체가 참조되면 Count 를 1 증가시키고, 반대로 참조 해제되어 Count 가 0이 되면 메모리에서 객체를 해제하는 기술입니다.
장점 : 컴파일 시점에 적용되므로, GC 대비 효율적입니다.
단점 : 순환 참조가 발생되어, Memory Leak 이 발생할 수 있습니다.
GC ( Garbage Collection )
사용 언어: Java, C# ...
참조 시점: Run time
런타임에 별도로 Garbage 를 관리하는 리소스를 실행합니다. 해당 리소스가 자동적으로 힙에 있는 객체를 해제하는 기술입니다.
장점 : 개발자가 별도로 동적 객체 관리할 필요가 없습니다.
단점 : 런타임에 객체를 추적, 해제하는 과정에서 오버헤드가 발생합니다. 또한 추가적인 메모리 소모가 존재합니다.
Swift ARC 에 대해서
Swift 는 RC 중 ARC (Automatic Reference Count) 라는 메모리 관리 기법을 사용합니다. 컴파일시에 동작하고 자동적으로 Release 코드를 중간에 넣어주어서 객체를 메모리에서 해제합니다. 수동적인 방법은 MRC (Manual Reference Count) 로서 Objective-c 에서 사용되었습니다.
RC 를 이용한 메모리 관리 기법은 GC 대비 효율적이지만 개발자가 메모리 구조에 대한 이해가 필요합니다. 단점으로는 개발자의 실수에 의하여 순환참조를 발생시킬 수 있습니다.
Swift 강한 순환 참조가 발생하는 경우
1. 프로퍼티에서 다른 인스턴스를 참조하는 경우
위 예제는 프로퍼티에서 각 인스턴스를 참조하여 Counting 이 1씩 증가한 경우입니다.
인스턴스 참조 변수를 nil 했기 때문에 내부 프로퍼티에 접근이 불가한 경우로 Memory Leak 이 발생합니다.
2. 탈출 클로저(Escaping Closure), 딜레이가 있는 클로저(Closure) 에서 참조하는 경우
클로저는 Heap 에 생성되며, 필요한 변수를 Capture 하는 동작을 수행합니다. 위 상황에서 Self를 Capture 하였기 때문에 Reference Counting 이 1 증가하게 되고 tom 에 nil 을 대입하여도 인스턴스가 해제되지 않습니다.
Swift 에서 강한 순환 참조를 방지하는 방법
1. 미소유 참조 (Unowned), 약한 참조 (weak) 사용하기
Unowned 혹은 weak 키워드로 인스턴스를 참조하면 Reference Counting 이 올라가지 않습니다.
Unowned 은 해당 인스턴스가 존재함을 확신할 때 사용하고 ( 생명주기가 더 길때 )
weak 는 옵셔널 타입으로, 인스턴스가 존재하지 않는 경우에 Optional Binding 혹은
Chaining 으로 크래시를 방지할 수 있습니다. ( 옵셔널 타입 )
2. Closure 에서 Capture List 작성하기
Capture List 는 Closure 가 참조할 대상과 참조 방식을 지정하는 형식입니다.
참조 타입이 아니라면 해당 요소는 클로저가 생성될 때 초기화 되지만 ( Value Type ) 그 외의 경우에는 Unowned, Weak 를 통해 얼마나 강하게 Capture 할지 지정할 수 있습니다.
Swift 는 Objective-c 처럼 직접 Reference Counting 을 관리해주지 않아도 되서 무척 편리하지만 다른 인스턴스를 참조할 때 메모리 구조에 대하여 한번 더 생각하고 참조 타입을 지정해야겠다는 생각을 했습니다.
클로저를 사용할 때 어떤 상황에서 weak 를 사용해야 하는지를 도표로 나타낸 사진입니다.
참고: https://medium.com/flawless-app-stories/you-dont-always-need-weak-self-a778bec505ef
'iOS Dev > Swift' 카테고리의 다른 글
iOS JSON 을 Decoding 하는 여러 가지 방식들 (0) | 2021.08.26 |
---|---|
지금까지 받았던 코드 리뷰 정리 ( iOS, Swift ) (0) | 2020.11.10 |
Swift Optional ( enum, wrapped ) 정리 (0) | 2020.10.12 |
윈도우 10 에서 Swift 5 사용하기 ( Visual Code, WSL ) (4) | 2020.08.01 |
iOS "UITableView Section Header 로드되지 않는 문제" 해결 (0) | 2020.07.26 |