티스토리 뷰

Swift&IOS

Swift의 메모리 관리 - ARC 001

밀쿄 2019. 10. 21. 18:05

안녕하세요. 밀쿄입니다.

오늘은 스위프트의 메모리관리에 대해서 알아보겠습니다.

프로그래밍에 있어서 메모리 관리는 매우 중요합니다..

메모리 관리를 잘못하면 앱이 죽어버리기도 하기 떄문이죠.

 

흔히 얘기하는 Unmanaged Language 와  Managed Language 라는게 있는데 ( 학술적인 용어는 아닙니다. )

Swift는  Managed Language라는 거죠.

그 말은 컴파일러가 알아서 해준다...라는거죠

참고로 대표적인 Unmanaged Languag는 C나 C++이 있을꺼고.. ( 동적할당과 해제 라는게 그래서 있죠 )

Managed Language 에는 가비지 콜렉터가 있는 자바가 있겠네요.

자 여튼 본론으로 돌아와서 컴파일러가 알아서 해주니까 된거 아냐? 라고 생각할 수 있는데

그러면 얼마나 좋겠습니까...만은 현실은 그렇지 않죠..

이 글에서는 전반적인 ARC와 ARC에 문제점에 대해서 살펴보겠습니다.

 

먼저 ARC가 어떻게 동작하냐? 이것부터 생각해봅시다.

클래스의 새 인스턴스를 만들 때 ARC는 적당한 크기의 메모리를 할당합니다.

그리고 그 공간이 더 이상 사용되지 않으면 해제합니다.

이 때 

사용중인 인스턴스를 해지하면 오류가 나기 떄문에

 할당 된 메모리를 참조할 때 마다 참초 횟수를 카운팅하고

그 카운터가 0이 되면 자동으로 메모리를 반환하는 원리로 돌아갑니다.

 

그래서 Automatic Reference Counting이라고 하는거죠?

 

자 그럼 코드를 한 번 봅시다.

이런 코드가 있습니다

변수를 3개를 선언하고 첫 번째 변수엔

인스턴스를 생성해 참조하도록 해봅시다.

그럼 init에 있는 print문이 출력될껍니다.

이 순간 레퍼런스 카운터가 하나가 증가합니다.

그럼 나머지 변수에 book1을 할당해줘봅시다.

 

그렇게되면 Book에 대한 참조 카운터가 3이 됩니다.

그 상태에서 book1과 book2를 해제하면 어떻게 될까요

보이는 것처럼 19번 째 줄에 의해 init에 있는 print문은 출력되었지만

아직까지 deinit에 있는 print문은 출력되지 않았습니다.

바로 book3로 인해 아직 레퍼런스 카운터가 1이 남아 있기 때문입니다.

여기서 book3도 해제해주면 어떻게 될까요?

deinit에 있는 print문이 잘 출력되는 것을 볼 수 있습니다

이것이 바로 ARC 입니다.

위에서 본것 처럼 객체 참조가 늘어나고 감소함에 따라 자동으로 카운트를 해줍니다.

 

괜히 Automatic Reference Counting이 아니겠죠?

 

더불어서 Swift에서는 프로그래머가 부르고 싶다고

deinit을 호출할 수 없고

해제에 대한 책임도 컴파일러가 가지고 있습니다,

 

여기까지만 보면 희망적이고 밝고 참 좋은데

처음 도입부에 언급한 것 처럼

현실은 그렇지 않습니다.

 

현실은 왜 그렇지 않은 지 한 번 살펴봅시다.

참조가 메모리에서 절대 해제 되지 않는 경우가 있습니다.

위에서 본 참조가 늘어날 때마다 참조 카운팅이 늘어나는 게

강한 참조(Strong Referce)라고 하는데 

이렇게만 돌아가면 순환 참조 문제가 발생합니다.

 코드를 보겠습니다..

이런 클래스를 추가해주고 아까 작성해둔 Book에 옵셔녈 변수로 추가하겠습니다.

지금보시면 Book이 클래스 변수로 Writer를 클래스의 인스턴스를 가지고 있고

Writer가 클래스 변수로 Book을 클래스 인스턴스로 소유하고 있습니다.

 

이제 변수를 만들어서 인스턴스를 생성해봅시다.

 여기까진 아무런 문제가 없습니다.

이 상황에 book1에 있는 writer에 writer1를

writer1에 있는 book에 book1을 할당해봅시다.

이렇게 말이죠.

이제 각 변수를 해제해봅시다.

해제가 되지 않습니다.

이렇게 프로그래머가 잘 해제되겠지? 라고 넘어가면

메모리 누수가 발생합니다.

 

이런 현상이 발생하므로 현실을 그렇지 않다고 했습니다.

그럼 이제 해결 해봅시다.

 

해결법은 두 가지가 있습니다

약한 참조랑 미소유 참조 입니다.

 

먼저 약한 참조부터 살펴보겠습니다.

약한 참조는 값은 참조하지만 소유하지 않습니다.

즉, 참조 카운터에 영향을 주지 않는다는거죠.

또한,  참조하고 있는 것이 먼저 메모리에서 해제되므로

약한참조로 선언된 참조 대상이 해지 되면

런타임에 자동으로 참조하고 있는 변수에 nil을 할당합니다.

여기서 알 수 있는 것은 nil이 될 수 있다는 것 때문에

var로 선언이 되어야하고 옵셔널 타입을 가저야 합니다.

그럼 이 해결법을 위 코드에 적용해보겠습니다.

weak로 선언했을 뿐인데

위와 달리 잘해제가 되는 것을 볼 수 있습니다.

 

두 번 째 해결방법은 미소유 참조입니다.

약한 참조랑 비슷하지면 가리키는 인스터스가

절대 해제되지 않을 것을 가정합니다.

쉽개말하면 메모리에서 해제되도

ARC가 해당 참조를 nil로 만들지 않습니다.

쉽게말하면 미소유는 옵셔녈타입이 아닙니다.

더불어서 만약 인스턴스가 해제됐는데

접근하게 되면 런타임 에러가 발생합니다.

 따라서 사용할 때 해당 객체의 생명주기가 참조와 같거나

더 길다는 것이 보장될 때 사용되어야 하죠..

 

자 이것도 사용해서 문제를 해결해봅시다.

 

이렇게 할 수 있습니다.

Writer 인스터스를 강하게 참조하고 있는 인스터스가 사라졌으므로 Writer가 해제 되고

해제됨에 따라 Book이 참조하고 있는 개체도 사라지므로 Book인스턴스도 메모리에서 해제됩니다.

참고로 이 때 해제가 되어서 상관없지만 Book의 writer는 nil이 안됩니다.

 

다음 시간에는 클로저에서는 어떤 경우가 발생하는 지 한 번 살펴보겠습니다.

 

 

참고자료

https://docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html

 

Automatic Reference Counting — The Swift Programming Language (Swift 5.1)

Automatic Reference Counting Swift uses Automatic Reference Counting (ARC) to track and manage your app’s memory usage. In most cases, this means that memory management “just works” in Swift, and you do not need to think about memory management yourself. A

docs.swift.org

https://jcsoohwancho.github.io/2019-08-13-Swift의-메모리-관리/

 

Swift의 메모리 관리법 - ARC

프로그래밍에 있어서 메모리 관리는 핵심적인 요소입니다. 메모리는 프로그램 자체가 돌아가는 공간이며, 프로그램이 필요로 하는 데이터가 사용할 수 있는 상태로 존재할 수 있는 곳이기도 합니다. 하지만 이 공간은 제한 되어 있기 때문에, 잘 관리되지 않으면 프로그램이 비효율적으로 동작하게 되고 최악의 경우 프로그램이 런타임 에러를 내면서 죽기도 합니다. 기본적으로는 이 메모리 관리의...

jcsoohwancho.github.io

 

'Swift&IOS' 카테고리의 다른 글

Sequence  (0) 2019.12.17
MVC(Model-View-Controller)?  (0) 2019.10.23
iOS13 바뀐 UIModalPresentationStyle에 관해서..  (0) 2019.10.02
다시 써보는 CoreData  (0) 2019.10.02
NotificationCenter  (0) 2019.10.01
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
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
글 보관함