[Swift] ARC(Automatic Reference Counting)

MSDev·2022년 2월 26일
0

Swift

목록 보기
2/2

오늘은 스위프트의 메모리 관리에 대해서 정리해보겠습니다. 항상 이름만 들었던 ARC... 왜 필요하고 어떤 방식으로 동작하는지 한번 정리해보고 싶어서 이렇게 글을 써봅니다.

이전 포스트에서 구조체와 클래스 에 대해서 정리를 해놨었는데 중요한 부분은 구조체 같은 값 형식은 인스턴스 생성시 메모리의 값이 복사되어 Stack 영역에 저장되고 클래스 같은 참조 형식은 인스턴스 생성시 Heap 영역에 값을 저장하고 Stack 영역에 메모리의 주소가 전달되어 사용된다 는 부분입니다.

메모리의 Heap 영역에 할당되는 데이터는 관리를 해야만 사용되지 않을 시 메모리에서 해제가 됩니다. 따라서 관리가 되지 않으면 메모리 누수(Memory Leak) 가 발생합니다.

사실 대부분의 경우는 Swift에서 자동으로 관리를 해줍니다. 바로 ARC 로요!

하지만 가끔씩 참조의 관계에 대해 더 많은 정보를 주어야 제대로 메모리 해제가 되는 경우가 있습니다. 강한 순환 참조 같은 경우가 있는데 관련한 내용을 다음 포스트에서라도 꼭 얘기를 해볼게요. 너무 길어질까봐요 ㅎㅎ

먼저 객체(object)의 lifetime에 대해 얘기해보면 객체는 init() (초기화)될 때 생겨나고 마지막 사용에서 끝나게 됩니다. ARC는 해당 객체의 lifetime이 끝나면 자동으로 메모리 해제를 시켜줍니다.

그럼 ARC는 어떻게 객체의 lifetime이 끝나는 줄 알까요?

바로 reference count를 통해, 쉽게 말해 참조하고 있는 숫자를 세서 객체의 lifetime을 추적합니다.

그럼 숫자는 어떻게 셀까요?

그건 Swift 컴파일러가!! retainrelease 연산자를 코드에 삽입시켜서 런타임에서 retain이 객체의 reference count를 1을 증가시키고 release가 reference count를 1을 감소하는 형식으로 작동합니다.
그리고 reference count가 0이 되면 해당 객체를 메모리 해제시키는 것이죠.

reference count 값도 Heap 영역에 함께 저장돼있어요!

ARC가 동작하는 방식을 그림으로 보겠습니다.
아래 그림을 보면 Traveler 객체가 생성되고 traveler1의 변수가 객체를 참조하기 시작하고 traveler1의 마지막 사용을 확인할 수 있습니다.

다음 아래 그림을 보시죠.
traveler1의 마지막 사용 아래 release 가 컴파일러에 의해 삽입돼요.
그런데 왜 retain 은 안들어갈까요?
바로

let traveler1 = Traveler(name: "Lily")

코드에서 Traveler 클래스의 객체를 만들어주는 초기화 함수(init())를 실행해줌으로써 retain 을 사용하지 않고도 reference count가 1이 증가하기 때문이죠.

다음으로

let traveler2 = traveler1

코드에서 traveler2 변수에는 객체의 메모리 주소가 복사되어 저장되겠죠? class 객체의 값의 저장 부분을 공부하시면 알 수 있어요!

이 때 traveler2가 객체를 참조하기 때문에 retain이 삽입되고 객체의 reference count가 1 증가합니다.

그럼 현재까지의 상황을 그림으로 보면 아래와 같습니다.

그리고 release를 실행시킴으로써 reference count를 1씩 감소시키며 0이 되면 Traveler의 객체가 메모리 해제가 되는 것이죠.

저도 처음 볼 땐 정말 이해가 안갔는데 참조 형식의 타입들이 메모리에 어떻게 저장되고 사용되는지 알고나서 보니까 이해가 되더라구요.

ARC의 기본 동작에 대해서 알아보았는데 다음에는 어떤 경우에 객체들의 사용이 끝났음에도 메모리 해제가 제대로 이뤄지지 않는지!
해당 경우에 대해서도 정리해보겠습니다.


[참고]

profile
iOS 개발자

0개의 댓글