[iOS] ARC에 대해서 알아보자. #11
jcrescent61
started this conversation in
iOS
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
-
WWDC2016 - UnderStanding swift performance - Reference Counting 아젠다를 보다보니....
ARC에 대해서 다시한번 정리해봐야겠다는 생각이든다.
메모리 관리를 왜 해야할까?
ARC에 대해서 알아보기에 앞서, 먼저 메모리 관리를 왜 해야하는지에 대해서 생각해보았다.
개인적으로 메모리 관리를 해야하는 이유는 물리적인 한계가 있기 때문이라고 생각한다.
메모리 용량이 무한하다면 관리할 필요 없이 프로젝트가 실행되고 종료될때까지 항상 실행되어있으면 되지만
실질적으로 메모리는 유한하기 때문이다.
ARC란?
Objective-C와 Swift에서 자동으로 메모리를 관리해주는 시스템이다. 그래서 Auto Reference Counting.
오직 참조 타입의 경우 해당되며 인스턴스가 참조되면 카운팅이 +1 참조되지 않으면 -1이되어
레퍼런스 카운팅이 0이 되면 메모리에서 해제되는 구조이다.
카운팅된 레퍼런스 수치는 어디에 저장될까?
위에 공유한 WWDC 내용을 보면 알 수 있듯 인스턴스 내부에서 소유있다고 발표되어있다.
해당 인스턴스를 참조하면서 +1 시켜주고 참조 해제할때 -1을 하는 것 같다.
주의) 위의 코드상에서 TestInstance를 참조하는 객체는 하나 뿐이지만 해당 파라미터로 들어가면서 카운팅은 2가 된다.
참조를 계산하는 시점은 언제일까?
ARC는 컴파일과 동시에 인스턴스를 메모리에서 해제하는 시점을 결정한다.
메모리 할당 ~ 해제 과정의 ARC
클래스의 인스턴스 생성
ARC가 인스턴스에 대한 정보를 저장하기 위해 메모리 공간 할당
해당 공간에 인스턴스의 타입 정보, 인스턴스와 관련된 저장 프로퍼티의 값 등을 저장
인스턴스의 카운팅이 0이되면 ARC가 인스턴스를 메모리에서 해제한다.
강한참조(Strong Reference)
값 타입에서 우리가 아무것도 입력하지 않고 인스턴스를 생성하면 사용되는 것이 바로 강한 참조이다.
앞서 설명했듯 메모리에 남아있으려면 레퍼런스 카운팅이 0이 되지 않아야한다.
강한 참조를 통해서 레퍼런스 카운팅을 +1 할 수 있고 다시 nil을 할당하면 레퍼런스 카운팅이 -1이 된다.
실험 결과
class ViewController: UIViewController {
}
(좌) print("인스턴스 할당") (우) print("인스턴스 해제") -> 접근하려니 에러가 뜬다.
메모리릭(Memory Leak) 만들기 - ARC의 단점
ARC가 자동적으로 메모리 관리를 해주는 것은 편리하지만 자동적으로 해주기 때문에 단점도 분명 존재한다.
실수로 순환참조가 발생하면 개발자의 의도에 맞지 않게 영원히 메모리에 해제되지 않는 단점이있다.
예시
ViewController <-> SomeView가 서로 참조하고 있는 형태이다. 이와 같은 경우에는 영원히 메모리에 남아있게 된다.
하지만 뷰에서 VC로 이벤트 전달해야하는데???
SwiftUI는 아직 능숙하지 않아 잘 모르지만 UIKit에서 VC에서 View로 데이터를 전달하는 경우도 있지만
반대로 View에서 발생한 인터렉션을 다시 VC에게 전달해줘야하는 로직이 분명히 필요하다.
이런 경우 어쩔 수 없이 순환 참조를 해야하는 걸까???? 그렇지 않다. 해결책은 바로 아래
약한참조(Weak Reference)
약한참조는 강한참조와는 다르게 인스턴스의 참조 횟수를 증가시키지 않는다.
변수 선언 앞에 weak를 입력해주면 해당 프로퍼티는 참조하는 인스턴스를 약한참조하게된다.
프로퍼티가 참조하는 인스턴스가 메모리에서 해제되면 자동으로 nil을 할당해준다.
약한참조 주의사항
위의 설명대로 약한참조는 언제든지 nil을 할당해줄수있어야하기 때문에
변수와 옵셔널로 구현되어있어야한다.
순환참조 해결하기
이와 같이 해결하면 weak var owner: Developer에서 약한참조를 하고있기 때문에 순환참조가 발생되지 않는다.
Developer와 MacBook은 서로 참조하고 있지만 MacBook.owner가 약한 참조를 하고 있기 때문에 메모리 릭이 발생하지 않는다.
위의 ViewController.view는 weak를 할당할 수 없는데?
UIViewController.view의 형태
이런 짓도 해봤다
맞는 말이다. 이미 구현되어있는 UIViewController.view를 바꿀순 없다.
하지만 외부에서 구현한 View를 할당한 경우 해당 뷰에 대한 인터렉션이나 데이터를 ViewController에 전달해줘야하는 경우는 꼭 발생한다. 이의 경우 Swift는 DIP의 형태로 구현하여 인터페이스를 바라보는 형태로 해결했다. 추후 Delegate Pattern과 DIP에 대해서 포스팅하겠다.
미소유참조(Unowned Reference)
어쩔때 쓰는지 잘 모르겠는 타입중 하나이다....
미소유참조도 약한참조와 같이 레퍼런스 카운팅을 증가시키지 않는다.
약한 참조는 nil이 될 수도 있다는 전제가 있지만 미소유참조는 항상 메모리에 존재할 것 처럼 동작한다.
약한 참조는 스스로 nil을 할당해주지만 미소유참조는 스스로 nil을 할당해주지 않기 때문이다.
따라서 미소유참조의 프로퍼티 타입은 옵셔널이 아닐 수도 있다.
미소유참조 주의사항
위의 설명대로라면 nil로 할당된 다음 참조하고자 하면 크래시가 날 수 있으므로 주의해야한다.
Beta Was this translation helpful? Give feedback.
All reactions