본문 바로가기
Swift Deeep Dive

[Swift] ARC의 정의와 발생될 수 있는 문제점

by shinhyogeun 2020. 7. 10.

나는 스위프트로 App을 만드는 것을 즐긴다. 하지만 초심자는 "이것이 과연 메모리(ex RAM)에 얼마나 영향(무게)을 줄 것인가"까지 고려하지는 않는다. 눈 앞의 구현도 벅차는게 현실이다. 그럼에도 더 나은 프로그램을 위해 ARC를 알면 좋다. ARC는 램에 영향을 줄이려고 만들어진 체계라고 보면 쉽다. 시작 전에 이 글은 docs.swift.org/swift-book/LanguageGuide/AutomaticReferenceCounting.html의 내용을 필자가 번역하며 쓴 글임을 밝힌다.

 

1. ARC란 무엇인가?

  ARC의 정의는 자동참조 카운팅으로 몇 번 인스턴스가 참조되는 지를 자동으로 파악하는 기술이다. 이것은 현재 스위프트와 Objective-C에서도 사용되고 있다. 

 

 인스턴스를 참조한다는 것은 쉽게 말해 Apple이라는 클래스가 있을 때 var apple = Apple() 이렇게 쓰면 여기서 Apple()이라는 인스턴스가  변수 apple에 의해 참조당하는 것이다.  이런 참조는 클로져도 가능하다는 것을 염두하자!(ex. var pear = () -> String {Code...} 이것은 pear라는 변수가 클로져 () -> String을 참조하는 것이다.)

 

 그러면 우리에게 Apple이라는 클래스가 있다고 할 때 만약 var apple = Apple() 이렇게 쓰면 우리는 이제 변수 apple이 클래스의 인스턴스를 참조했다는 것을 알 수 있다. ARC는 이것을 알아채고 인스턴스 참조가 1번 일어났다고 세어주는 기술이다. 

 

 ARC는 이렇게 참조의 갯수를 파악해주고 참조의 수가 0이 되면 그 인스턴스를 메모리에서 해제하는 것도 기능으로 가지고 있다. 이것이 무슨 이야기이냐면 우리가 var apple = Apple()이라고 해서 인스턴스 참조 수가 1일 때 어느 순간 우리가 apple = nil 이라고 한다면 apple은 더 이상 Apple이라는 클래스의 인스턴스를 참조하지 않는 것이다. 그러면 ARC가 이것을 알아채고 참조 수를 0으로 바꾸고 Apple()을 메모리에서 해제 즉 다시 말하면 Apple()을 램에서 제거하고 다른 작업을 위한 공간으로 활용할 것이라는 뜻이다.

 

2. ARC가 불러올 수 있는 문제점

 

 문제점을 알기 전에 지금까지 말한 참조는 일어날 때 1이 증가하고 이러한 참조를 "강한참조"라고 말한다. 참조했을 때 참조 수가 1이

증가하면 그것은 강한참조라고 생각하면 쉽다.

 

 자 그러면 이제 문제점을 볼 차례이다.

 

 ARC는 클래스의 인스턴스의 참조 수가 0이 아니면 절대 메모리에서 해제하지 않기 때문에 메모리 낭비가 일어날 수 있다.

 

  예를 들어 다음의 코드와 그림을 보자!

Person 클래스와 Apartment 클래스를 정의하고 있다. 각각의 클래스 내부에서 서로의 클래스 타입을 가지는 변수를 소유한다.

john이라는 변수가 Person(name: "John Appleseed")라는 클래스 인스턴스를 강한참조하고

unit4A라는 변수는 Apartment(unit:"4A")라는 클래스 인스턴스를 강한참조하고 있다!!

여기가 중요한 부분이다.

변수 john의 변수 apratment(엄밀하게는 변수apartment가 속해있는 클래스의 인스턴스를 참조하는 변수john)가 unit4A를 참조한다!!!

unit4A는 Apratment클래스의 인스턴스를 참조하고 unit4A를 다시 apartment가 참조하니 Apartment클래스 인스턴스의 참조 수가 2가 된다. 반대도 똑같다. 그러면 결론적으로 Person 클래스의 인스턴스 참조 수와 Apartment 클래스의 인스턴스 참조 수가 모두 "2"이다. 그리고 밑의 그림이 머리 속에 그려져야 한다.

여기서 우리가 john = nil, unit4A = nil이라고 코드를 적으면 각각의 참조 수가 1개씩 줄어들어 밑의 그림처럼 된다.

그런데 여기서 우리는 아직 참조 수가 1개 남아서 두 클래스의 인스턴스는 메모리에 남아있게 되지만 클래스 인스턴스를 모두 nil로 해버려서 저기 강한참조를 제거하기위해 접근하는 것이 불가능하고 계속 메모리를 먹게된다.. 이게 바로 문제다.이 문제를 해결하기 위해서 우리는 참조해도 참조 수를 증가시키지 않는 약한참조 혹은 비소유참조를 사용해야 한다.

 

---------해결책은 다음 글에서 계속됩니다!!----------