Swift의 메모리 관리

Zeto·2022년 4월 27일
0

Swift_Study

목록 보기
17/18

우리는 프로젝트를 진행함에 있어 프로퍼티나 메서드 등의 여러 기능과 작업 요소들을 마주하게 되는데, 이때 메모리에 대한 신경을 쓸 수 밖에 없다.
앱의 성능을 위해서는 필연적으로 메모리를 관리하고 유지해 줄 필요가 있으며, 이러한 것들이 제대로 이뤄지지 않는다면 사용되지 않는 데이터가 메모리에 계속 남아있는 'Memory Leak'이나 메모리 할당이 해제된 주소로 접근하는 'Dangling Pointer' 등의 여러 문제에 직면하게 될 수 있다.
그렇지만 swift로 작업하는 우리는 이런 메모리 관리를 직접적으로 다뤄본 기억이 없을 것이다. 그렇다면 이러한 관리는 대체 어떻게 이뤄지는 걸까?

Swift의 ARC(Automatic Reference Counting)

우리의 iOS는 참으로 고맙게도 앱의 메모리 사용에 대한 추적 및 관리를 위해 ARC라는 기능을 사용한다. Automatic Reference Counting의 줄임말로서 참조 시에 참조 카운팅을 업 시키고, 해제 시에는 카운팅을 다운시켜주다 참조횟수가 0이 될 때 인스턴스를 메모리에서 해제시켜주는 방식으로 참조 메모리 관리를 자동적으로 해주는 편리한 기능이다.
(해당 작업은 런타임이 아닌, 컴파일 시점에서 실행된다)

Strong | Weak | Unowned

이처럼 메모리 참조와 관련해서 swift는 세가지의 키워드를 가지고 있다. 먼저 강한 참조인 Strong은 인스턴스의 주소값이 프로퍼티에 할당될 때, 무조건 RC 값이 증가하는 방식으로 우리가 아무런 키워드 없이 인스턴스를 생성해서 사용할 때 자연스럽게 사용된 방식이다.

대부분 이런 방식으로 인스턴스를 할당하였을 테지만, strong 방식은 순환 참조라는 아쉬운 요소가 존재한다.

  • 순환 참조
    두 객체가 서로를 참조하고 있는 형태로서 각각의 인스턴스를 해제하더라도 서로를 참조하고 있는 인스턴스는 해제되지 않아 메모리에서 해제되지 않고 영구적으로 남아 메모리의 누수를 일으키는 문제를 야기할 수 있다.

물론 이러한 인스턴스가 얼마 되지 않는다면 큰 문제가 되지는 않을 수 있지만, 프로젝트의 볼륨이 커질 수록 당연히 더 많은 인스턴스를 사용하게 될 테고 그러다보면 언젠가는 메모리가 이를 감당할 수 없는 지경에 이를 수도 있다.

그렇다면 이러한 문제를 우리는 어떻게 해결할 수 있을까?

| Weak (약한 참조)

먼저 약한 참조라고 불리는 weak 키워드를 사용하는 방법이 있다. 이 키워드는 이름 그대로 약한 녀석이라 인스턴스를 참조하더라도 RC를 증가시키지 않고, 참조하던 인스턴스가 해제될 경우 자동으로 nil을 할당하여 메모리에서 해제가 되도록 해준다.

따라서 생성 이후, 각 객체 간에 서로 참조를 하게 되는 상황에서 weak을 적절히 사용하게 된다면 RC 값이 증가하지 않으므로 순환 참조의 늪에 빠지지 않을 수 있다.
(보통 delegate와 관련하여 weak 키워드가 자주 사용됨)

다만 앞서 말했 듯이 인스턴스 해제 시에 자동으로 nil이 할당되기 때문에 해당 프로퍼티는 무조건 옵셔널로 선언되어야 하는 점을 잊지 않아야 한다.

| Unowned (미소유 참조)

미소유 참조라 불리는 unowned 키워드는 사실 weak 키워드와 어마어마한 차이가 있는 것은 아니다. 강한 참조로 인한 순환 참조 문제 해결에 용이하며, RC 값을 증가시키지 않는다는 큰 공통점도 가지고 있다.

다만 해당 키워드는 인스턴스를 참조하는 도중에 해당 인스턴스가 메모리에서 해제될 가능성이 전혀 없다고 확신한다는 의미를 가진다.
즉, 참조하던 인스턴스가 해제될 경우 nil을 할당받지 못 하고 해제된 메모리 주소값을 돌게 되는데 마치 옵셔널을 강제 해제하는 것 같이 위험해 보인다.

따라서 이렇게 unowned로 선언된 프로퍼티가 참조하던 인스턴스가 메모리에서 먼저 해제될 경우, 접근에 대한 에러를 발생시켜주게 된다.

이런 점 때문에 보통 순환 참조를 해결하기 위해 주로 weak 키워드를 활용한다.

profile
중2병도 iOS가 하고싶어

0개의 댓글